Auto merge of #145074 - tgross35:rollup-0tillrm, r=tgross35

Rollup of 9 pull requests

Successful merges:

 - rust-lang/rust#144705 (compiler-builtins: plumb LSE support for aarch64 on linux/gnu when optimized-compiler-builtins not enabled)
 - rust-lang/rust#144857 (Port `#[allow_internal_unsafe]` to the new attribute system)
 - rust-lang/rust#144900 (Stabilize `unsigned_signed_diff` feature)
 - rust-lang/rust#144903 (Rename `begin_panic_handler` to `panic_handler`)
 - rust-lang/rust#144974 (compiler-builtins subtree update)
 - rust-lang/rust#145007 (Fix build/doc/test of error index generator)
 - rust-lang/rust#145018 (Derive `Hash` for rustc_public types)
 - rust-lang/rust#145045 (doc(library): Fix Markdown in `Iterator::by_ref`)
 - rust-lang/rust#145046 (Fix doc comment of File::try_lock and File::try_lock_shared)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-08-08 02:59:15 +00:00
commit 67d45f49e0
197 changed files with 825 additions and 716 deletions

View file

@ -113,3 +113,11 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser {
Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
}
}
pub(crate) struct AllowInternalUnsafeParser;
impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
const PATH: &[Symbol] = &[sym::allow_internal_unsafe];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
}

View file

@ -33,7 +33,9 @@ use crate::attributes::lint_helpers::{
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::macro_attrs::{MacroEscapeParser, MacroUseParser};
use crate::attributes::macro_attrs::{
AllowInternalUnsafeParser, MacroEscapeParser, MacroUseParser,
};
use crate::attributes::must_use::MustUseParser;
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
use crate::attributes::non_exhaustive::NonExhaustiveParser;
@ -178,6 +180,7 @@ attribute_parsers!(
Single<SkipDuringMethodDispatchParser>,
Single<TransparencyParser>,
Single<WithoutArgs<AllowIncoherentImplParser>>,
Single<WithoutArgs<AllowInternalUnsafeParser>>,
Single<WithoutArgs<AsPtrParser>>,
Single<WithoutArgs<AutomaticallyDerivedParser>>,
Single<WithoutArgs<CoherenceIsCoreParser>>,

View file

@ -905,10 +905,7 @@ impl SyntaxExtension {
find_attr!(attrs, AttributeKind::AllowInternalUnstable(i, _) => i)
.map(|i| i.as_slice())
.unwrap_or_default();
// FIXME(jdonszelman): allow_internal_unsafe isn't yet new-style
// let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe);
let allow_internal_unsafe =
ast::attr::find_by_name(attrs, sym::allow_internal_unsafe).is_some();
let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe(_));
let local_inner_macros = ast::attr::find_by_name(attrs, sym::macro_export)
.and_then(|macro_export| macro_export.meta_item_list())

View file

@ -249,6 +249,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_allow_incoherent_impl]`.
AllowIncoherentImpl(Span),
/// Represents `#[allow_internal_unsafe]`.
AllowInternalUnsafe(Span),
/// Represents `#[allow_internal_unstable]`.
AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span),

View file

@ -16,6 +16,7 @@ impl AttributeKind {
Align { .. } => No,
AllowConstFnUnstable(..) => No,
AllowIncoherentImpl(..) => No,
AllowInternalUnsafe(..) => Yes,
AllowInternalUnstable(..) => Yes,
AsPtr(..) => Yes,
AutomaticallyDerived(..) => Yes,

View file

@ -14,6 +14,7 @@
//! [`crate::late_lint_methods!`] invocation in `lib.rs`.
use std::fmt::Write;
use std::slice;
use ast::token::TokenKind;
use rustc_abi::BackendRepr;
@ -21,6 +22,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::visit::{FnCtxt, FnKind};
use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust::expr_to_string;
use rustc_attr_parsing::AttributeParser;
use rustc_errors::{Applicability, LintDiagnostic};
use rustc_feature::GateIssue;
use rustc_hir as hir;
@ -249,7 +251,16 @@ impl UnsafeCode {
impl EarlyLintPass for UnsafeCode {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
if attr.has_name(sym::allow_internal_unsafe) {
if AttributeParser::parse_limited(
cx.builder.sess(),
slice::from_ref(attr),
sym::allow_internal_unsafe,
attr.span,
DUMMY_NODE_ID,
Some(cx.builder.features()),
)
.is_some()
{
self.report_unsafe(cx, attr.span, BuiltinUnsafe::AllowInternalUnsafe);
}
}

View file

@ -29,7 +29,7 @@ passes_allow_incoherent_impl =
`rustc_allow_incoherent_impl` attribute should be applied to impl items
.label = the only currently supported targets are inherent methods
passes_allow_internal_unstable =
passes_macro_only_attribute =
attribute should be applied to a macro
.label = not a macro

View file

@ -207,6 +207,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => {
self.check_const_continue(hir_id, *attr_span, target)
}
Attribute::Parsed(AttributeKind::AllowInternalUnsafe(attr_span)) => {
self.check_allow_internal_unsafe(hir_id, *attr_span, span, target, attrs)
}
Attribute::Parsed(AttributeKind::AllowInternalUnstable(_, first_span)) => {
self.check_allow_internal_unstable(hir_id, *first_span, span, target, attrs)
}
@ -413,7 +416,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
// internal
| sym::prelude_import
| sym::panic_handler
| sym::allow_internal_unsafe
| sym::lang
| sym::needs_allocator
| sym::default_lib_allocator
@ -2212,7 +2214,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
/// (Allows proc_macro functions)
// FIXME(jdonszelmann): if possible, move to attr parsing
fn check_allow_internal_unstable(
&self,
hir_id: HirId,
@ -2220,6 +2221,42 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
span: Span,
target: Target,
attrs: &[Attribute],
) {
self.check_macro_only_attr(
hir_id,
attr_span,
span,
target,
attrs,
"allow_internal_unstable",
)
}
/// Outputs an error for `#[allow_internal_unsafe]` which can only be applied to macros.
/// (Allows proc_macro functions)
fn check_allow_internal_unsafe(
&self,
hir_id: HirId,
attr_span: Span,
span: Span,
target: Target,
attrs: &[Attribute],
) {
self.check_macro_only_attr(hir_id, attr_span, span, target, attrs, "allow_internal_unsafe")
}
/// Outputs an error for attributes that can only be applied to macros, such as
/// `#[allow_internal_unsafe]` and `#[allow_internal_unstable]`.
/// (Allows proc_macro functions)
// FIXME(jdonszelmann): if possible, move to attr parsing
fn check_macro_only_attr(
&self,
hir_id: HirId,
attr_span: Span,
span: Span,
target: Target,
attrs: &[Attribute],
attr_name: &str,
) {
match target {
Target::Fn => {
@ -2238,18 +2275,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
// erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm => {
self.inline_attr_str_error_without_macro_def(
hir_id,
attr_span,
"allow_internal_unstable",
);
self.inline_attr_str_error_without_macro_def(hir_id, attr_span, attr_name);
return;
}
// otherwise continue out of the match
_ => {}
}
self.tcx.dcx().emit_err(errors::AllowInternalUnstable { attr_span, span });
self.tcx.dcx().emit_err(errors::MacroOnlyAttribute { attr_span, span });
}
/// Checks if the items on the `#[debugger_visualizer]` attribute are valid.

View file

@ -643,8 +643,8 @@ pub(crate) struct UsedStatic {
}
#[derive(Diagnostic)]
#[diag(passes_allow_internal_unstable)]
pub(crate) struct AllowInternalUnstable {
#[diag(passes_macro_only_attribute)]
pub(crate) struct MacroOnlyAttribute {
#[primary_span]
pub attr_span: Span,
#[label]

View file

@ -349,7 +349,7 @@ impl AssertMessage {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum BinOp {
Add,
AddUnchecked,
@ -384,7 +384,7 @@ impl BinOp {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum UnOp {
Not,
Neg,
@ -490,7 +490,7 @@ pub enum StatementKind {
Nop,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum Rvalue {
/// Creates a pointer with the indicated mutability to the place.
///
@ -666,7 +666,7 @@ impl Rvalue {
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum AggregateKind {
Array(Ty),
Tuple,
@ -677,14 +677,14 @@ pub enum AggregateKind {
RawPtr(Ty, Mutability),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum Operand {
Copy(Place),
Move(Place),
Constant(ConstOperand),
}
#[derive(Clone, Eq, PartialEq, Serialize)]
#[derive(Clone, Eq, PartialEq, Hash, Serialize)]
pub struct Place {
pub local: Local,
/// projection out of a place (access a field, deref a pointer, etc)
@ -697,7 +697,7 @@ impl From<Local> for Place {
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct ConstOperand {
pub span: Span,
pub user_ty: Option<UserTypeAnnotationIndex>,
@ -770,7 +770,7 @@ pub enum VarDebugInfoContents {
// ProjectionElem<Local, Ty>) and user-provided type annotations (for which the projection elements
// are of type ProjectionElem<(), ()>).
// In rustc_public's IR we don't need this generality, so we just use ProjectionElem for Places.
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum ProjectionElem {
/// Dereference projections (e.g. `*_1`) project to the address referenced by the base place.
Deref,
@ -913,7 +913,7 @@ impl SwitchTargets {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum BorrowKind {
/// Data must be immutable and is aliasable.
Shared,
@ -940,7 +940,7 @@ impl BorrowKind {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum RawPtrKind {
Mut,
Const,
@ -958,14 +958,14 @@ impl RawPtrKind {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum MutBorrowKind {
Default,
TwoPhaseBorrow,
ClosureCapture,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum FakeBorrowKind {
/// A shared (deep) borrow. Data must be immutable and is aliasable.
Deep,
@ -982,13 +982,13 @@ pub enum Mutability {
Mut,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum Safety {
Safe,
Unsafe,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum PointerCoercion {
/// Go from a fn-item type to a fn-pointer type.
ReifyFnPointer,
@ -1015,7 +1015,7 @@ pub enum PointerCoercion {
Unsize,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum CastKind {
// FIXME(smir-rename): rename this to PointerExposeProvenance
PointerExposeAddress,
@ -1030,7 +1030,7 @@ pub enum CastKind {
Transmute,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum NullOp {
/// Returns the size of a value of that type.
SizeOf,

View file

@ -113,7 +113,7 @@ pub enum Pattern {
}
/// Represents a constant in the type system
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct TyConst {
pub(crate) kind: TyConstKind,
pub id: TyConstId,
@ -140,7 +140,7 @@ impl TyConst {
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum TyConstKind {
Param(ParamConst),
Bound(DebruijnIndex, BoundVar),
@ -151,11 +151,11 @@ pub enum TyConstKind {
ZSTValue(Ty),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct TyConstId(usize);
/// Represents a constant in MIR
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct MirConst {
/// The constant kind.
pub(crate) kind: ConstantKind,
@ -212,17 +212,17 @@ impl MirConst {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
pub struct MirConstId(usize);
type Ident = Opaque;
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct Region {
pub kind: RegionKind,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum RegionKind {
ReEarlyParam(EarlyParamRegion),
ReBound(DebruijnIndex, BoundRegion),
@ -233,7 +233,7 @@ pub enum RegionKind {
pub(crate) type DebruijnIndex = u32;
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct EarlyParamRegion {
pub index: u32,
pub name: Symbol,
@ -241,7 +241,7 @@ pub struct EarlyParamRegion {
pub(crate) type BoundVar = u32;
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct BoundRegion {
pub var: BoundVar,
pub kind: BoundRegionKind,
@ -249,13 +249,13 @@ pub struct BoundRegion {
pub(crate) type UniverseIndex = u32;
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct Placeholder<T> {
pub universe: UniverseIndex,
pub bound: T,
}
#[derive(Clone, Copy, PartialEq, Eq, Serialize)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub struct Span(usize);
impl Debug for Span {
@ -997,7 +997,7 @@ crate_def! {
}
/// A list of generic arguments.
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct GenericArgs(pub Vec<GenericArgKind>);
impl std::ops::Index<ParamTy> for GenericArgs {
@ -1016,7 +1016,7 @@ impl std::ops::Index<ParamConst> for GenericArgs {
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum GenericArgKind {
Lifetime(Region),
Type(Ty),
@ -1199,7 +1199,7 @@ pub enum BoundTyKind {
Param(ParamDef, String),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum BoundRegionKind {
BrAnon,
BrNamed(BrNamedDef, String),
@ -1354,7 +1354,7 @@ impl Allocation {
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub enum ConstantKind {
Ty(TyConst),
Allocated(Allocation),
@ -1365,13 +1365,13 @@ pub enum ConstantKind {
ZeroSized,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct ParamConst {
pub index: u32,
pub name: String,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
pub struct UnevaluatedConst {
pub def: ConstDef,
pub args: GenericArgs,

View file

@ -34,7 +34,9 @@ jobs:
- 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"
- run: |
set -eo pipefail # Needed to actually fail the job if ci-util fails
python3 ci/ci-util.py generate-matrix | tee "$GITHUB_OUTPUT"
id: script
test:
@ -50,7 +52,6 @@ jobs:
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
@ -70,8 +71,12 @@ jobs:
os: ubuntu-24.04
- target: powerpc64le-unknown-linux-gnu
os: ubuntu-24.04
- target: powerpc64le-unknown-linux-gnu
os: ubuntu-24.04-ppc64le
- target: riscv64gc-unknown-linux-gnu
os: ubuntu-24.04
- target: s390x-unknown-linux-gnu
os: ubuntu-24.04-s390x
- target: thumbv6m-none-eabi
os: ubuntu-24.04
- target: thumbv7em-none-eabi
@ -88,10 +93,8 @@ jobs:
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
@ -102,11 +105,23 @@ jobs:
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 $HOME
shell: bash
run: |
set -x
echo "${HOME:-not found}"
pwd
printenv
- name: Print runner information
run: uname -a
# Native ppc and s390x runners don't have rustup by default
- name: Install rustup
if: matrix.os == 'ubuntu-24.04-ppc64le' || matrix.os == 'ubuntu-24.04-s390x'
run: sudo apt-get update && sudo apt-get install -y rustup
- uses: actions/checkout@v4
- name: Install Rust (rustup)
shell: bash
@ -117,7 +132,12 @@ jobs:
rustup update "$channel" --no-self-update
rustup default "$channel"
rustup target add "${{ matrix.target }}"
# Our scripts use nextest if possible. This is skipped on the native ppc
# and s390x runners since install-action doesn't support them.
- uses: taiki-e/install-action@nextest
if: "!(matrix.os == 'ubuntu-24.04-ppc64le' || matrix.os == 'ubuntu-24.04-s390x')"
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
@ -144,7 +164,7 @@ 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
@ -256,7 +276,7 @@ jobs:
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
@ -311,8 +331,8 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Install stable `rustfmt`
run: rustup set profile minimal && rustup default stable && rustup component add rustfmt
- name: Install nightly `rustfmt`
run: rustup set profile minimal && rustup default nightly && rustup component add rustfmt
- run: cargo fmt -- --check
extensive:

View file

@ -12,12 +12,13 @@ jobs:
if: github.repository == 'rust-lang/compiler-builtins'
uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@main
with:
github-app-id: ${{ vars.APP_CLIENT_ID }}
# https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/compiler-builtins.20subtree.20sync.20automation/with/528482375
zulip-stream-id: 219381
zulip-topic: 'compiler-builtins subtree sync automation'
zulip-bot-email: "compiler-builtins-ci-bot@rust-lang.zulipchat.com"
zulip-bot-email: "compiler-builtins-ci-bot@rust-lang.zulipchat.com"
pr-base-branch: master
branch-name: rustc-pull
secrets:
zulip-api-token: ${{ secrets.ZULIP_API_TOKEN }}
token: ${{ secrets.GITHUB_TOKEN }}
github-app-secret: ${{ secrets.APP_PRIVATE_KEY }}

View file

@ -37,8 +37,9 @@ default = ["compiler-builtins"]
# implementations and also filling in unimplemented intrinsics
c = ["dep:cc"]
# Workaround for the Cranelift codegen backend. Disables any implementations
# which use inline assembly and fall back to pure Rust versions (if available).
# For implementations where there is both a generic version and a platform-
# specific version, use the generic version. This is meant to enable testing
# the generic versions on all platforms.
no-asm = []
# Workaround for codegen backends which haven't yet implemented `f16` and

View file

@ -40,11 +40,7 @@ mod intrinsics {
x as f64
}
#[cfg(all(
f16_enabled,
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(all(f16_enabled, f128_enabled))]
pub fn extendhftf(x: f16) -> f128 {
x as f128
}
@ -201,11 +197,7 @@ mod intrinsics {
/* f128 operations */
#[cfg(all(
f16_enabled,
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(all(f16_enabled, f128_enabled))]
pub fn trunctfhf(x: f128) -> f16 {
x as f16
}
@ -220,50 +212,32 @@ mod intrinsics {
x as f64
}
#[cfg(all(
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(f128_enabled)]
pub fn fixtfsi(x: f128) -> i32 {
x as i32
}
#[cfg(all(
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(f128_enabled)]
pub fn fixtfdi(x: f128) -> i64 {
x as i64
}
#[cfg(all(
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(f128_enabled)]
pub fn fixtfti(x: f128) -> i128 {
x as i128
}
#[cfg(all(
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(f128_enabled)]
pub fn fixunstfsi(x: f128) -> u32 {
x as u32
}
#[cfg(all(
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(f128_enabled)]
pub fn fixunstfdi(x: f128) -> u64 {
x as u64
}
#[cfg(all(
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(f128_enabled)]
pub fn fixunstfti(x: f128) -> u128 {
x as u128
}
@ -540,47 +514,25 @@ fn run() {
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"))
))]
#[cfg(all(f16_enabled, f128_enabled))]
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"))
))]
#[cfg(f128_enabled)]
bb(fixtfdi(bb(2.)));
#[cfg(all(
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(f128_enabled)]
bb(fixtfsi(bb(2.)));
#[cfg(all(
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(f128_enabled)]
bb(fixtfti(bb(2.)));
bb(fixunsdfti(bb(2.)));
bb(fixunssfti(bb(2.)));
#[cfg(all(
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(f128_enabled)]
bb(fixunstfdi(bb(2.)));
#[cfg(all(
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(f128_enabled)]
bb(fixunstfsi(bb(2.)));
#[cfg(all(
f128_enabled,
not(any(target_arch = "powerpc", target_arch = "powerpc64"))
))]
#[cfg(f128_enabled)]
bb(fixunstfti(bb(2.)));
#[cfg(f128_enabled)]
bb(floatditf(bb(2)));
@ -616,11 +568,7 @@ fn run() {
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"))
))]
#[cfg(all(f16_enabled, f128_enabled))]
bb(trunctfhf(bb(2.)));
#[cfg(f128_enabled)]
bb(trunctfsf(bb(2.)));

View file

@ -365,7 +365,6 @@ float_bench! {
/* float -> unsigned int */
#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))]
float_bench! {
name: conv_f32_u32,
sig: (a: f32) -> u32,
@ -387,7 +386,6 @@ float_bench! {
],
}
#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))]
float_bench! {
name: conv_f32_u64,
sig: (a: f32) -> u64,
@ -409,7 +407,6 @@ float_bench! {
],
}
#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))]
float_bench! {
name: conv_f32_u128,
sig: (a: f32) -> u128,
@ -505,7 +502,6 @@ float_bench! {
/* float -> signed int */
#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))]
float_bench! {
name: conv_f32_i32,
sig: (a: f32) -> i32,
@ -527,7 +523,6 @@ float_bench! {
],
}
#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))]
float_bench! {
name: conv_f32_i64,
sig: (a: f32) -> i64,
@ -549,7 +544,6 @@ float_bench! {
],
}
#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))]
float_bench! {
name: conv_f32_i128,
sig: (a: f32) -> i128,
@ -666,9 +660,6 @@ pub fn float_conv() {
conv_f64_i128(&mut criterion);
#[cfg(f128_enabled)]
// FIXME: ppc64le has a sporadic overflow panic in the crate functions
// <https://github.com/rust-lang/compiler-builtins/issues/617#issuecomment-2125914639>
#[cfg(not(all(target_arch = "powerpc64", target_endian = "little")))]
{
conv_u32_f128(&mut criterion);
conv_u64_f128(&mut criterion);

View file

@ -110,9 +110,7 @@ float_bench! {
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);

View file

@ -121,9 +121,7 @@ float_bench! {
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);
@ -133,11 +131,8 @@ pub fn float_trunc() {
#[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);
}

View file

@ -17,28 +17,14 @@ pub fn skip_sys_checks(test_name: &str) -> bool {
"extend_f16_f32",
"trunc_f32_f16",
"trunc_f64_f16",
// FIXME(#616): re-enable once fix is in nightly
// <https://github.com/rust-lang/compiler-builtins/issues/616>
"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.
// <https://github.com/rust-lang/compiler-builtins/issues/617#issuecomment-2125914639>
const PPC64LE_SKIPPED: &[&str] = &["extend_f32_f128"];
// FIXME(f16_f128): system symbols have incorrect results
// <https://github.com/rust-lang/compiler-builtins/issues/617#issuecomment-2125914639>
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.
// <https://github.com/llvm/llvm-project/issues/91840>
const AARCH64_SKIPPED: &[&str] = &["mul_f128", "div_f128"];
// FIXME(llvm): system symbols have incorrect results on Windows
// <https://github.com/rust-lang/compiler-builtins/issues/617#issuecomment-2121359807>
const WINDOWS_SKIPPED: &[&str] = &[
@ -57,19 +43,7 @@ pub fn skip_sys_checks(test_name: &str) -> bool {
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) {
if cfg!(x86_no_sse) && X86_NO_SSE_SKIPPED.contains(&test_name) {
return true;
}

View file

@ -111,7 +111,7 @@ macro_rules! float_sum {
}
}
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
#[cfg(not(x86_no_sse))]
mod float_addsub {
use super::*;
@ -122,7 +122,7 @@ mod float_addsub {
}
#[cfg(f128_enabled)]
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
#[cfg(not(x86_no_sse))]
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
mod float_addsub_f128 {
use super::*;

View file

@ -59,32 +59,28 @@ mod i_to_f {
|| ((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,
);
}
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.
// Test against native conversion.
// FIXME(x86,ppc): the platform version has rounding bugs on i686 and
// PowerPC64le (for PPC this only shows up in Docker, not the native runner).
// https://github.com/rust-lang/compiler-builtins/pull/384#issuecomment-740413334
if !Float::eq_repr(f0, f1) && !cfg!(any(
target_arch = "x86",
target_arch = "powerpc",
target_arch = "powerpc64"
all(target_arch = "powerpc64", target_endian = "little")
)) {
panic!(
"{}({}): std: {:?}, builtins: {:?}",

View file

@ -138,7 +138,7 @@ macro_rules! float {
};
}
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
#[cfg(not(x86_no_sse))]
mod float_div {
use super::*;

View file

@ -1,7 +1,7 @@
#![allow(unused_macros)]
#![cfg_attr(f128_enabled, feature(f128))]
#![cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
#[cfg_attr(x86_no_sse, allow(unused))]
use builtins_test::*;
// This is approximate because of issues related to
@ -52,6 +52,7 @@ macro_rules! pow {
};
}
#[cfg(not(x86_no_sse))] // FIXME(i586): failure for powidf2
pow! {
f32, 1e-4, __powisf2, all();
f64, 1e-12, __powidf2, all();

View file

@ -1,6 +1,6 @@
#![feature(decl_macro)] // so we can use pub(super)
#![feature(macro_metavar_expr_concat)]
#![cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "no-asm")))]
#![cfg(all(target_arch = "aarch64", target_os = "linux"))]
/// Translate a byte size to a Rust type.
macro int_ty {

View file

@ -113,7 +113,7 @@ macro_rules! float_mul {
};
}
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
#[cfg(not(x86_no_sse))]
mod float_mul {
use super::*;
@ -126,7 +126,7 @@ mod float_mul {
}
#[cfg(f128_enabled)]
#[cfg(not(all(target_arch = "x86", not(target_feature = "sse"))))]
#[cfg(not(x86_no_sse))]
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
mod float_mul_f128 {
use super::*;

View file

@ -7,10 +7,12 @@ git history.
import json
import os
import pprint
import re
import subprocess as sp
import sys
from dataclasses import dataclass
from functools import cache
from glob import glob
from inspect import cleandoc
from os import getenv
@ -50,15 +52,6 @@ GIT = ["git", "-C", REPO_ROOT]
DEFAULT_BRANCH = "master"
WORKFLOW_NAME = "CI" # Workflow that generates the benchmark artifacts
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
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.
@ -70,7 +63,7 @@ IGNORE_FILES = [
# 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).*"
TRIGGER_LIBM_CI_FILE_PAT = ".*(libm|musl).*"
TYPES = ["f16", "f32", "f64", "f128"]
@ -80,6 +73,54 @@ def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
@dataclass(init=False)
class PrCfg:
"""Directives that we allow in the commit body to control test behavior.
These are of the form `ci: foo`, at the start of a line.
"""
# Skip regression checks (must be at the start of a line).
allow_regressions: bool = False
# Don't run extensive tests
skip_extensive: bool = False
# 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: bool = False
# Max number of extensive tests to run by default
MANY_EXTENSIVE_THRESHOLD: int = 20
# Run tests for `libm` that may otherwise be skipped due to no changed files.
always_test_libm: bool = False
# String values of directive names
DIR_ALLOW_REGRESSIONS: str = "allow-regressions"
DIR_SKIP_EXTENSIVE: str = "skip-extensive"
DIR_ALLOW_MANY_EXTENSIVE: str = "allow-many-extensive"
DIR_TEST_LIBM: str = "test-libm"
def __init__(self, body: str):
directives = re.finditer(r"^\s*ci:\s*(?P<dir_name>\S*)", body, re.MULTILINE)
for dir in directives:
name = dir.group("dir_name")
if name == self.DIR_ALLOW_REGRESSIONS:
self.allow_regressions = True
elif name == self.DIR_SKIP_EXTENSIVE:
self.skip_extensive = True
elif name == self.DIR_ALLOW_MANY_EXTENSIVE:
self.allow_many_extensive = True
elif name == self.DIR_TEST_LIBM:
self.always_test_libm = True
else:
eprint(f"Found unexpected directive `{name}`")
exit(1)
pprint.pp(self)
@dataclass
class PrInfo:
"""GitHub response for PR query"""
@ -88,10 +129,21 @@ class PrInfo:
commits: list[str]
created_at: str
number: int
cfg: PrCfg
@classmethod
def load(cls, pr_number: int | str) -> Self:
"""For a given PR number, query the body and commit list"""
def from_env(cls) -> Self | None:
"""Create a PR object from the PR_NUMBER environment if set, `None` otherwise."""
pr_env = os.environ.get("PR_NUMBER")
if pr_env is not None and len(pr_env) > 0:
return cls.from_pr(pr_env)
return None
@classmethod
@cache # Cache so we don't print info messages multiple times
def from_pr(cls, pr_number: int | str) -> Self:
"""For a given PR number, query the body and commit list."""
pr_info = sp.check_output(
[
"gh",
@ -104,13 +156,9 @@ class PrInfo:
],
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)
pr_json = json.loads(pr_info)
eprint("PR info:", json.dumps(pr_json, indent=4))
return cls(**json.loads(pr_info), cfg=PrCfg(pr_json["body"]))
class FunctionDef(TypedDict):
@ -207,26 +255,32 @@ class Context:
"""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)
# Always run on merge CI
if not self.is_pr():
return False
return False
pr = PrInfo.from_env()
assert pr is not None, "Is a PR but couldn't load PrInfo"
# Allow opting in to libm tests
if pr.cfg.always_test_libm:
return False
# By default, run if there are any changed files matching the pattern
return all(not re.match(TRIGGER_LIBM_CI_FILE_PAT, str(f)) for f in self.changed)
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.
"""
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
)
pr = PrInfo.from_env()
if pr is not None:
skip_tests = pr.cfg.skip_extensive
error_on_many_tests = not pr.cfg.allow_many_extensive
if skip_tests:
eprint("Skipping all extensive tests")
@ -253,16 +307,14 @@ class Context:
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:
if error_on_many_tests and total_to_test > PrCfg.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"
f"More than {PrCfg.MANY_EXTENSIVE_THRESHOLD} tests would be run; add"
f" `{PrCfg.DIR_ALLOW_MANY_EXTENSIVE}` 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."
f" files, `{PrCfg.DIR_SKIP_EXTENSIVE}` can be used instead."
)
exit(1)
@ -371,8 +423,8 @@ def handle_bench_regressions(args: list[str]):
eprint(USAGE)
exit(1)
pr = PrInfo.load(pr_number)
if pr.contains_directive(REGRESSION_DIRECTIVE):
pr = PrInfo.from_pr(pr_number)
if pr.cfg.allow_regressions:
eprint("PR allows regressions")
return

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \
@ -12,6 +12,5 @@ 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

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -1,4 +1,4 @@
ARG IMAGE=ubuntu:24.04
ARG IMAGE=ubuntu:25.04
FROM $IMAGE
RUN apt-get update && \

View file

@ -97,7 +97,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:24.04 (or rustlang/rust:nightly).
ubuntu:25.04 (or rustlang/rust:nightly).
"
exit
fi

View file

@ -41,7 +41,10 @@ else
"${test_builtins[@]}" --benches
"${test_builtins[@]}" --benches --release
if [ "${TEST_VERBATIM:-}" = "1" ]; then
# Validate that having a verbatim path for the target directory works
# (trivial to regress using `/` in paths to build artifacts rather than
# `Path::join`). MinGW does not currently support these paths.
if [[ "$target" = *"windows"* ]] && [[ "$target" != *"gnu"* ]]; then
verb_path=$(cmd.exe //C echo \\\\?\\%cd%\\builtins-test\\target2)
"${test_builtins[@]}" --target-dir "$verb_path" --features c
fi
@ -161,7 +164,7 @@ 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
@ -204,7 +207,7 @@ else
"${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.

View file

@ -3,7 +3,7 @@
set -eux
url=git://git.musl-libc.org/musl
url=https://github.com/kraj/musl.git
ref=c47ad25ea3b484e10326f933e927c0bc8cded3da
dst=crates/musl-math-sys/musl

View file

@ -35,8 +35,9 @@ default = ["compiler-builtins"]
# implementations and also filling in unimplemented intrinsics
c = ["dep:cc"]
# Workaround for the Cranelift codegen backend. Disables any implementations
# which use inline assembly and fall back to pure Rust versions (if available).
# For implementations where there is both a generic version and a platform-
# specific version, use the generic version. This is meant to enable testing
# the generic versions on all platforms.
no-asm = []
# Workaround for codegen backends which haven't yet implemented `f16` and

View file

@ -106,13 +106,6 @@ fn configure_libm(target: &Target) {
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

View file

@ -1,6 +1,5 @@
// Configuration that is shared between `compiler_builtins` and `builtins_test`.
use std::process::{Command, Stdio};
use std::{env, str};
#[derive(Debug)]
@ -35,26 +34,6 @@ impl Target {
.map(|s| s.to_lowercase().replace("_", "-"))
.collect();
// Query rustc for options that Cargo does not provide env for. The bootstrap hack is used
// to get consistent output regardless of channel (`f16`/`f128` config options are hidden
// on stable otherwise).
let mut cmd = Command::new(env::var("RUSTC").unwrap());
cmd.args(["--print=cfg", "--target", &triple])
.env("RUSTC_BOOTSTRAP", "1")
.stderr(Stdio::inherit());
let out = cmd
.output()
.unwrap_or_else(|e| panic!("failed to run `{cmd:?}`: {e}"));
let rustc_cfg = str::from_utf8(&out.stdout).unwrap();
// If we couldn't query `rustc` (e.g. a custom JSON target was used), make the safe
// choice and leave `f16` and `f128` disabled.
let rustc_output_ok = out.status.success();
let reliable_f128 =
rustc_output_ok && rustc_cfg.lines().any(|l| l == "target_has_reliable_f128");
let reliable_f16 =
rustc_output_ok && rustc_cfg.lines().any(|l| l == "target_has_reliable_f16");
Self {
triple,
triple_split,
@ -74,8 +53,10 @@ impl Target {
.split(",")
.map(ToOwned::to_owned)
.collect(),
reliable_f128,
reliable_f16,
// Note that these are unstable options, so only show up with the nightly compiler or
// with `RUSTC_BOOTSTRAP=1` (which is required to use the types anyway).
reliable_f128: env::var_os("CARGO_CFG_TARGET_HAS_RELIABLE_F128").is_some(),
reliable_f16: env::var_os("CARGO_CFG_TARGET_HAS_RELIABLE_F16").is_some(),
}
}
@ -100,6 +81,13 @@ pub fn configure_aliases(target: &Target) {
println!("cargo:rustc-cfg=thumb_1")
}
// 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");
}
/* Not all backends support `f16` and `f128` to the same level on all architectures, so we
* need to disable things if the compiler may crash. See configuration at:
* * https://github.com/rust-lang/rust/blob/c65dccabacdfd6c8a7f7439eba13422fdd89b91e/compiler/rustc_codegen_llvm/src/llvm_util.rs#L367-L432

View file

@ -4,7 +4,7 @@ use core::intrinsics;
intrinsics! {
#[unsafe(naked)]
#[cfg(all(target_os = "uefi", not(feature = "no-asm")))]
#[cfg(target_os = "uefi")]
pub unsafe extern "custom" fn __chkstk() {
core::arch::naked_asm!(
".p2align 2",

View file

@ -6,9 +6,6 @@
//! 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:
@ -24,7 +21,18 @@
//! 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.
use core::sync::atomic::{AtomicU8, Ordering};
/// non-zero if the host supports LSE atomics.
static HAVE_LSE_ATOMICS: AtomicU8 = AtomicU8::new(0);
intrinsics! {
/// Call to enable LSE in outline atomic operations. The caller must verify
/// LSE operations are supported.
pub extern "C" fn __rust_enable_lse() {
HAVE_LSE_ATOMICS.store(1, Ordering::Relaxed);
}
}
/// Translate a byte size to a Rust type.
#[rustfmt::skip]
@ -45,6 +53,7 @@ macro_rules! reg {
(2, $num:literal) => { concat!("w", $num) };
(4, $num:literal) => { concat!("w", $num) };
(8, $num:literal) => { concat!("x", $num) };
(16, $num:literal) => { concat!("x", $num) };
}
/// Given an atomic ordering, translate it to the acquire suffix for the lxdr aarch64 ASM instruction.
@ -126,6 +135,41 @@ macro_rules! stxp {
};
}
// If supported, perform the requested LSE op and return, or fallthrough.
macro_rules! try_lse_op {
($op: literal, $ordering:ident, $bytes:tt, $($reg:literal,)* [ $mem:ident ] ) => {
concat!(
".arch_extension lse; ",
"adrp x16, {have_lse}; ",
"ldrb w16, [x16, :lo12:{have_lse}]; ",
"cbz w16, 8f; ",
// LSE_OP s(reg),* [$mem]
concat!(lse!($op, $ordering, $bytes), $( " ", reg!($bytes, $reg), ", " ,)* "[", stringify!($mem), "]; ",),
"ret; ",
"8:"
)
};
}
// Translate memory ordering to the LSE suffix
#[rustfmt::skip]
macro_rules! lse_mem_sfx {
(Relaxed) => { "" };
(Acquire) => { "a" };
(Release) => { "l" };
(AcqRel) => { "al" };
}
// Generate the aarch64 LSE operation for memory ordering and width
macro_rules! lse {
($op:literal, $order:ident, 16) => {
concat!($op, "p", lse_mem_sfx!($order))
};
($op:literal, $order:ident, $bytes:tt) => {
concat!($op, lse_mem_sfx!($order), size!($bytes))
};
}
/// See <https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicI8.html#method.compare_and_swap>.
macro_rules! compare_and_swap {
($ordering:ident, $bytes:tt, $name:ident) => {
@ -137,7 +181,9 @@ macro_rules! compare_and_swap {
) -> int_ty!($bytes) {
// We can't use `AtomicI8::compare_and_swap`; we *are* compare_and_swap.
core::arch::naked_asm! {
// UXT s(tmp0), s(0)
// CAS s(0), s(1), [x2]; if LSE supported.
try_lse_op!("cas", $ordering, $bytes, 0, 1, [x2]),
// UXT s(tmp0), s(0)
concat!(uxt!($bytes), " ", reg!($bytes, 16), ", ", reg!($bytes, 0)),
"0:",
// LDXR s(0), [x2]
@ -150,6 +196,7 @@ macro_rules! compare_and_swap {
"cbnz w17, 0b",
"1:",
"ret",
have_lse = sym crate::aarch64_linux::HAVE_LSE_ATOMICS,
}
}
}
@ -166,6 +213,8 @@ macro_rules! compare_and_swap_i128 {
expected: i128, desired: i128, ptr: *mut i128
) -> i128 {
core::arch::naked_asm! {
// CASP x0, x1, x2, x3, [x4]; if LSE supported.
try_lse_op!("cas", $ordering, 16, 0, 1, 2, 3, [x4]),
"mov x16, x0",
"mov x17, x1",
"0:",
@ -179,6 +228,7 @@ macro_rules! compare_and_swap_i128 {
"cbnz w15, 0b",
"1:",
"ret",
have_lse = sym crate::aarch64_linux::HAVE_LSE_ATOMICS,
}
}
}
@ -195,6 +245,8 @@ macro_rules! swap {
left: int_ty!($bytes), right_ptr: *mut int_ty!($bytes)
) -> int_ty!($bytes) {
core::arch::naked_asm! {
// SWP s(0), s(0), [x1]; if LSE supported.
try_lse_op!("swp", $ordering, $bytes, 0, 0, [x1]),
// mov s(tmp0), s(0)
concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)),
"0:",
@ -204,6 +256,7 @@ macro_rules! swap {
concat!(stxr!($ordering, $bytes), " w17, ", reg!($bytes, 16), ", [x1]"),
"cbnz w17, 0b",
"ret",
have_lse = sym crate::aarch64_linux::HAVE_LSE_ATOMICS,
}
}
}
@ -212,7 +265,7 @@ macro_rules! swap {
/// See (e.g.) <https://doc.rust-lang.org/stable/std/sync/atomic/struct.AtomicI8.html#method.fetch_add>.
macro_rules! fetch_op {
($ordering:ident, $bytes:tt, $name:ident, $op:literal) => {
($ordering:ident, $bytes:tt, $name:ident, $op:literal, $lse_op:literal) => {
intrinsics! {
#[maybe_use_optimized_c_shim]
#[unsafe(naked)]
@ -220,6 +273,8 @@ macro_rules! fetch_op {
val: int_ty!($bytes), ptr: *mut int_ty!($bytes)
) -> int_ty!($bytes) {
core::arch::naked_asm! {
// LSEOP s(0), s(0), [x1]; if LSE supported.
try_lse_op!($lse_op, $ordering, $bytes, 0, 0, [x1]),
// mov s(tmp0), s(0)
concat!("mov ", reg!($bytes, 16), ", ", reg!($bytes, 0)),
"0:",
@ -231,6 +286,7 @@ macro_rules! fetch_op {
concat!(stxr!($ordering, $bytes), " w15, ", reg!($bytes, 17), ", [x1]"),
"cbnz w15, 0b",
"ret",
have_lse = sym crate::aarch64_linux::HAVE_LSE_ATOMICS,
}
}
}
@ -240,25 +296,25 @@ 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" }
fetch_op! { $ordering, $bytes, $name, "add", "ldadd" }
};
}
macro_rules! and {
($ordering:ident, $bytes:tt, $name:ident) => {
fetch_op! { $ordering, $bytes, $name, "bic" }
fetch_op! { $ordering, $bytes, $name, "bic", "ldclr" }
};
}
macro_rules! xor {
($ordering:ident, $bytes:tt, $name:ident) => {
fetch_op! { $ordering, $bytes, $name, "eor" }
fetch_op! { $ordering, $bytes, $name, "eor", "ldeor" }
};
}
macro_rules! or {
($ordering:ident, $bytes:tt, $name:ident) => {
fetch_op! { $ordering, $bytes, $name, "orr" }
fetch_op! { $ordering, $bytes, $name, "orr", "ldset" }
};
}

View file

@ -1,5 +1,3 @@
#![cfg(not(feature = "no-asm"))]
// Interfaces used by naked trampolines.
// SAFETY: these are defined in compiler-builtins
unsafe extern "C" {

View file

@ -1,5 +1,3 @@
#![cfg(not(feature = "no-asm"))]
use core::arch::global_asm;
global_asm!(include_str!("hexagon/func_macro.s"), options(raw));

View file

@ -60,7 +60,7 @@ 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"),))]
#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
pub mod aarch64_linux;
#[cfg(all(

View file

@ -44,8 +44,6 @@
#![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"))]

View file

@ -9,10 +9,7 @@ use core::intrinsics;
intrinsics! {
#[unsafe(naked)]
#[cfg(all(
any(all(windows, target_env = "gnu"), target_os = "uefi"),
not(feature = "no-asm")
))]
#[cfg(any(all(windows, target_env = "gnu"), target_os = "uefi"))]
pub unsafe extern "custom" fn __chkstk() {
core::arch::naked_asm!(
"jmp {}", // Jump to __alloca since fallthrough may be unreliable"
@ -21,10 +18,7 @@ intrinsics! {
}
#[unsafe(naked)]
#[cfg(all(
any(all(windows, target_env = "gnu"), target_os = "uefi"),
not(feature = "no-asm")
))]
#[cfg(any(all(windows, target_env = "gnu"), target_os = "uefi"))]
pub unsafe extern "custom" fn _alloca() {
// __chkstk and _alloca are the same function
core::arch::naked_asm!(

View file

@ -9,14 +9,7 @@ use core::intrinsics;
intrinsics! {
#[unsafe(naked)]
#[cfg(all(
any(
all(windows, target_env = "gnu"),
target_os = "cygwin",
target_os = "uefi"
),
not(feature = "no-asm")
))]
#[cfg(any(all(windows, target_env = "gnu"), target_os = "cygwin", target_os = "uefi"))]
pub unsafe extern "custom" fn ___chkstk_ms() {
core::arch::naked_asm!(
"push %rcx",

View file

@ -40,8 +40,6 @@ macro_rules! functions {
) => {
// 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() {
<fn($($aty),+) -> $rty>::check(super::$name);
}

View file

@ -5,8 +5,7 @@ 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" }
object = "0.37.1"
serde_json = "1.0.140"
[features]

View file

@ -271,18 +271,6 @@ impl MaybeOverride<(f32,)> for SpecialCase {
impl MaybeOverride<(f64,)> for SpecialCase {
fn check_float<F: 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
@ -292,16 +280,6 @@ impl MaybeOverride<(f64,)> for SpecialCase {
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)
{

View file

@ -1,9 +1,9 @@
// Configuration shared with both libm and libm-test
use std::env;
use std::path::PathBuf;
use std::process::{Command, Stdio};
use std::{env, str};
#[derive(Debug)]
#[allow(dead_code)]
pub struct Config {
pub manifest_dir: PathBuf,
@ -33,26 +33,6 @@ impl Config {
.map(|s| s.to_lowercase().replace("_", "-"))
.collect();
// Query rustc for options that Cargo does not provide env for. The bootstrap hack is used
// to get consistent output regardless of channel (`f16`/`f128` config options are hidden
// on stable otherwise).
let mut cmd = Command::new(env::var("RUSTC").unwrap());
cmd.args(["--print=cfg", "--target", &target_triple])
.env("RUSTC_BOOTSTRAP", "1")
.stderr(Stdio::inherit());
let out = cmd
.output()
.unwrap_or_else(|e| panic!("failed to run `{cmd:?}`: {e}"));
let rustc_cfg = str::from_utf8(&out.stdout).unwrap();
// If we couldn't query `rustc` (e.g. a custom JSON target was used), make the safe
// choice and leave `f16` and `f128` disabled.
let rustc_output_ok = out.status.success();
let reliable_f128 =
rustc_output_ok && rustc_cfg.lines().any(|l| l == "target_has_reliable_f128");
let reliable_f16 =
rustc_output_ok && rustc_cfg.lines().any(|l| l == "target_has_reliable_f16");
Self {
target_triple,
manifest_dir: PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()),
@ -66,8 +46,10 @@ impl Config {
target_string: env::var("TARGET").unwrap(),
target_vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(),
target_features,
reliable_f128,
reliable_f16,
// Note that these are unstable options, so only show up with the nightly compiler or
// with `RUSTC_BOOTSTRAP=1` (which is required to use the types anyway).
reliable_f128: env::var_os("CARGO_CFG_TARGET_HAS_RELIABLE_F128").is_some(),
reliable_f16: env::var_os("CARGO_CFG_TARGET_HAS_RELIABLE_F16").is_some(),
}
}
}

View file

@ -59,7 +59,7 @@ 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.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(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;

View file

@ -33,7 +33,7 @@ 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.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn acosf(x: f32) -> f32 {
let x1p_120 = f32::from_bits(0x03800000); // 0x1p-120 === 2 ^ (-120)

View file

@ -7,7 +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)]
#[cfg_attr(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;

View file

@ -7,7 +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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn acoshf(x: f32) -> f32 {
let u = x.to_bits();
let a = u & 0x7fffffff;

View file

@ -1,37 +1,62 @@
//! Architecture-specific support for x86-32 without SSE2
//!
//! We 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.
//!
//! See https://github.com/rust-lang/compiler-builtins/pull/976 for discussion on why these
//! functions are implemented in this way.
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;
pub fn ceil(mut x: f64) -> f64 {
unsafe {
core::arch::asm!(
"fld qword ptr [{x}]",
// Save the FPU control word, using `x` as scratch space.
"fstcw [{x}]",
// Set rounding control to 0b10 (+∞).
"mov word ptr [{x} + 2], 0x0b7f",
"fldcw [{x} + 2]",
// Round.
"frndint",
// Restore FPU control word.
"fldcw [{x}]",
// Save rounded value to memory.
"fstp qword ptr [{x}]",
x = in(reg) &mut x,
// All the x87 FPU stack is used, all registers must be clobbered
out("st(0)") _, out("st(1)") _,
out("st(2)") _, out("st(3)") _,
out("st(4)") _, out("st(5)") _,
out("st(6)") _, out("st(7)") _,
options(nostack),
);
}
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;
pub fn floor(mut x: f64) -> f64 {
unsafe {
core::arch::asm!(
"fld qword ptr [{x}]",
// Save the FPU control word, using `x` as scratch space.
"fstcw [{x}]",
// Set rounding control to 0b01 (-∞).
"mov word ptr [{x} + 2], 0x077f",
"fldcw [{x} + 2]",
// Round.
"frndint",
// Restore FPU control word.
"fldcw [{x}]",
// Save rounded value to memory.
"fstp qword ptr [{x}]",
x = in(reg) &mut x,
// All the x87 FPU stack is used, all registers must be clobbered
out("st(0)") _, out("st(1)") _,
out("st(2)") _, out("st(3)") _,
out("st(4)") _, out("st(5)") _,
out("st(6)") _, out("st(7)") _,
options(nostack),
);
}
x
}

View file

@ -66,7 +66,7 @@ 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.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn asin(mut x: f64) -> f64 {
let z: f64;
let r: f64;

View file

@ -35,7 +35,7 @@ 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.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(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)

View file

@ -7,7 +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)]
#[cfg_attr(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;

View file

@ -7,7 +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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn asinhf(mut x: f32) -> f32 {
let u = x.to_bits();
let i = u & 0x7fffffff;

View file

@ -65,7 +65,7 @@ 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.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(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;

View file

@ -47,7 +47,7 @@ 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.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(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;

View file

@ -23,7 +23,7 @@ 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.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(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;

View file

@ -41,7 +41,7 @@ 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.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(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)

View file

@ -5,7 +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)]
#[cfg_attr(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;

View file

@ -5,7 +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)]
#[cfg_attr(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;

View file

@ -8,7 +8,7 @@ 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn cbrt(x: f64) -> f64 {
cbrt_round(x, Round::Nearest).val
}

View file

@ -25,7 +25,7 @@ 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn cbrtf(x: f32) -> f32 {
let x1p24 = f32::from_bits(0x4b800000); // 0x1p24f === 2 ^ 24

View file

@ -2,7 +2,7 @@
///
/// Finds the nearest integer greater than or equal to `x`.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ceilf16(x: f16) -> f16 {
super::generic::ceil(x)
}
@ -10,7 +10,7 @@ pub fn ceilf16(x: f16) -> f16 {
/// Ceil (f32)
///
/// Finds the nearest integer greater than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ceilf(x: f32) -> f32 {
select_implementation! {
name: ceilf,
@ -24,7 +24,7 @@ pub fn ceilf(x: f32) -> f32 {
/// Ceil (f64)
///
/// Finds the nearest integer greater than or equal to `x`.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ceil(x: f64) -> f64 {
select_implementation! {
name: ceil,
@ -40,7 +40,7 @@ pub fn ceil(x: f64) -> f64 {
///
/// Finds the nearest integer greater than or equal to `x`.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn ceilf128(x: f128) -> f128 {
super::generic::ceil(x)
}

View file

@ -3,7 +3,7 @@
/// 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn copysignf16(x: f16, y: f16) -> f16 {
super::generic::copysign(x, y)
}
@ -12,7 +12,7 @@ pub fn copysignf16(x: f16, y: f16) -> 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn copysignf(x: f32, y: f32) -> f32 {
super::generic::copysign(x, y)
}
@ -21,7 +21,7 @@ pub fn copysignf(x: f32, y: f32) -> 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn copysign(x: f64, y: f64) -> f64 {
super::generic::copysign(x, y)
}
@ -31,7 +31,7 @@ pub fn copysign(x: f64, y: f64) -> f64 {
/// 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn copysignf128(x: f128, y: f128) -> f128 {
super::generic::copysign(x, y)
}

View file

@ -45,7 +45,7 @@ use super::{k_cos, k_sin, rem_pio2};
/// The cosine of `x` (f64).
///
/// `x` is specified in radians.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn cos(x: f64) -> f64 {
let ix = (f64::to_bits(x) >> 32) as u32 & 0x7fffffff;

View file

@ -27,7 +27,7 @@ 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn cosf(x: f32) -> f32 {
let x64 = x as f64;

View file

@ -5,7 +5,7 @@ use super::{exp, expm1, k_expo2};
/// 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn cosh(mut x: f64) -> f64 {
/* |x| */
let mut ix = x.to_bits();

View file

@ -5,7 +5,7 @@ use super::{expf, expm1f, k_expo2f};
/// 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn coshf(mut x: f32) -> f32 {
let x1p120 = f32::from_bits(0x7b800000); // 0x1p120f === 2 ^ 120

View file

@ -219,7 +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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn erf(x: f64) -> f64 {
let r: f64;
let s: f64;

View file

@ -130,7 +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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn erff(x: f32) -> f32 {
let r: f32;
let s: f32;

View file

@ -81,7 +81,7 @@ 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).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(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

View file

@ -7,7 +7,7 @@ const P10: &[f64] = &[
];
/// Calculates 10 raised to the power of `x` (f64).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(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();

View file

@ -7,7 +7,7 @@ const P10: &[f32] = &[
];
/// Calculates 10 raised to the power of `x` (f32).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn exp10f(x: f32) -> f32 {
let (mut y, n) = modff(x);
let u = n.to_bits();

View file

@ -322,7 +322,7 @@ static TBL: [u64; TBLSIZE * 2] = [
/// 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)]
#[cfg_attr(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);

View file

@ -73,7 +73,7 @@ static EXP2FT: [u64; TBLSIZE] = [
/// 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)]
#[cfg_attr(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);

View file

@ -30,7 +30,7 @@ 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).
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(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 ??????????? */

View file

@ -30,7 +30,7 @@ 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.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn expm1(mut x: f64) -> f64 {
let hi: f64;
let lo: f64;

View file

@ -32,7 +32,7 @@ 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.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn expm1f(mut x: f32) -> f32 {
let x1p127 = f32::from_bits(0x7f000000); // 0x1p127f === 2 ^ 127

View file

@ -1,7 +1,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) */
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(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;

View file

@ -3,7 +3,7 @@
/// 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fabsf16(x: f16) -> f16 {
super::generic::fabs(x)
}
@ -12,7 +12,7 @@ pub fn fabsf16(x: f16) -> 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fabsf(x: f32) -> f32 {
select_implementation! {
name: fabsf,
@ -27,7 +27,7 @@ pub fn fabsf(x: f32) -> 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fabs(x: f64) -> f64 {
select_implementation! {
name: fabs,
@ -43,7 +43,7 @@ pub fn fabs(x: f64) -> f64 {
/// 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)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fabsf128(x: f128) -> f128 {
super::generic::fabs(x)
}

View file

@ -7,7 +7,7 @@
///
/// A range error may occur.
#[cfg(f16_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fdimf16(x: f16, y: f16) -> f16 {
super::generic::fdim(x, y)
}
@ -20,7 +20,7 @@ pub fn fdimf16(x: f16, y: f16) -> f16 {
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fdimf(x: f32, y: f32) -> f32 {
super::generic::fdim(x, y)
}
@ -33,7 +33,7 @@ pub fn fdimf(x: f32, y: f32) -> f32 {
/// * NAN if either argument is NAN.
///
/// A range error may occur.
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fdim(x: f64, y: f64) -> f64 {
super::generic::fdim(x, y)
}
@ -47,7 +47,7 @@ pub fn fdim(x: f64, y: f64) -> f64 {
///
/// A range error may occur.
#[cfg(f128_enabled)]
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
#[cfg_attr(assert_no_panic, no_panic::no_panic)]
pub fn fdimf128(x: f128, y: f128) -> f128 {
super::generic::fdim(x, y)
}

Some files were not shown because too many files have changed in this diff Show more