Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,9 @@ fn codegen_float_intrinsic_call<'tcx>(
sym::sinf64 => ("sin", 1, fx.tcx.types.f64, types::F64),
sym::sinf128 => ("sinf128", 1, fx.tcx.types.f128, types::F128),

sym::tanhf32 => ("tanhf", 1, fx.tcx.types.f32, types::F32),
sym::tanhf64 => ("tanh", 1, fx.tcx.types.f64, types::F64),

sym::cosf16 => return false, // has a fallback via f32
sym::cosf32 => ("cosf", 1, fx.tcx.types.f32, types::F32),
sym::cosf64 => ("cos", 1, fx.tcx.types.f64, types::F64),
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
sym::powif64 => "__builtin_powi",
sym::sinf32 => "sinf",
sym::sinf64 => "sin",
sym::tanhf32 => "tanhf",
sym::tanhf64 => "tanh",
sym::cosf32 => "cosf",
sym::cosf64 => "cos",
sym::powf32 => "powf",
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ fn call_simple_intrinsic<'ll, 'tcx>(
sym::sinf64 => ("llvm.sin", &[bx.type_f64()]),
sym::sinf128 => ("llvm.sin", &[bx.type_f128()]),

sym::tanhf32 => ("llvm.tanh", &[bx.type_f32()]),
sym::tanhf64 => ("llvm.tanh", &[bx.type_f64()]),

sym::cosf16 => ("llvm.cos", &[bx.type_f16()]),
sym::cosf32 => ("llvm.cos", &[bx.type_f32()]),
sym::cosf64 => ("llvm.cos", &[bx.type_f64()]),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ impl CodegenBackend for LlvmCodegenBackend {
sym::integer_min,

// Fallback via libm, but the LLVM intrinsic is used instead.
sym::tanhf32, sym::tanhf64,
sym::sinf16, sym::sinf32, sym::sinf64,
sym::cosf16, sym::cosf32, sym::cosf64,
sym::powf16, sym::powf32, sym::powf64,
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_hir_analysis/src/check/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
| sym::sqrtf64
| sym::sqrtf128
| sym::sub_with_overflow
| sym::tanhf32
| sym::tanhf64
| sym::three_way_compare
| sym::truncf16
| sym::truncf32
Expand Down Expand Up @@ -446,6 +448,9 @@ pub(crate) fn check_intrinsic_type(
sym::sinf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::sinf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),

sym::tanhf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::tanhf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),

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),
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2099,6 +2099,8 @@ symbols! {
sync,
synthetic,
t32,
tanhf32,
tanhf64,
target,
target_abi,
target_arch,
Expand Down
13 changes: 13 additions & 0 deletions library/core/src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,19 @@ pub fn sinf32(x: f32) -> f32 {
pub fn sinf64(x: f64) -> f64 {
libm::likely_available::sin(x)
}
#[inline]
#[rustc_intrinsic]
#[rustc_nounwind]
pub fn tanhf64(x: f64) -> f64 {
libm::likely_available::tanh(x)
}
#[inline]
#[rustc_intrinsic]
#[rustc_nounwind]
pub fn tanhf32(x: f32) -> f32 {
libm::likely_available::tanhf(x)
}

/// Returns the sine of an `f128`.
///
/// The stabilized version of this intrinsic is
Expand Down
4 changes: 1 addition & 3 deletions library/std/src/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,8 +1047,6 @@ impl f32 {
///
/// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
/// can even differ within the same execution from one invocation to the next.
/// This function currently corresponds to the `tanhf` from libc on Unix
/// and Windows. Note that this might change in the future.
///
/// # Examples
///
Expand All @@ -1068,7 +1066,7 @@ impl f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn tanh(self) -> f32 {
cmath::tanhf(self)
intrinsics::tanhf32(self)
}

/// Inverse hyperbolic sine function.
Expand Down
4 changes: 1 addition & 3 deletions library/std/src/num/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,8 +1047,6 @@ impl f64 {
///
/// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
/// can even differ within the same execution from one invocation to the next.
/// This function currently corresponds to the `tanh` from libc on Unix
/// and Windows. Note that this might change in the future.
///
/// # Examples
///
Expand All @@ -1068,7 +1066,7 @@ impl f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn tanh(self) -> f64 {
cmath::tanh(self)
intrinsics::tanhf64(self)
}

/// Inverse hyperbolic sine function.
Expand Down
1 change: 0 additions & 1 deletion library/std/src/sys/cmath.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ unsafe extern "C" {
pub safe fn log1pf(n: f32) -> f32;
pub safe fn sinh(n: f64) -> f64;
pub safe fn tan(n: f64) -> f64;
pub safe fn tanh(n: f64) -> f64;
pub safe fn tgamma(n: f64) -> f64;
pub safe fn tgammaf(n: f32) -> f32;
pub safe fn lgamma_r(n: f64, s: &mut i32) -> f64;
Expand Down
48 changes: 48 additions & 0 deletions tests/codegen-llvm/intrinsics/tanh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//@ revisions: DEV OPT
//@ [DEV] compile-flags: -C no-prepopulate-passes
//@ [OPT] compile-flags: -O

// We previously lowered tanh to libm calls, which would set errno and thus prevent a couple of
// optimizations, since LLVM would mark the call as `memory(errnomem: write)`.
// LLVM since gained additional math intrinsics, including tanh, to which we're now lowering
// instead. They are marked as `readnone`, and thus allow the optimizations shown below.

#![crate_type = "lib"]

// CHECK-LABEL: @tanhf64
#[no_mangle]
pub fn tanhf64(x: f64) -> f64 {
// CHECK: call double @llvm.tanh.f64
// CHECK-NOT: call double @tanh(
x.tanh()
}

// CHECK-LABEL: @tanhf32
#[no_mangle]
pub fn tanhf32(x: f32) -> f32 {
// CHECK: call float @llvm.tanh.f32
// CHECK-NOT: call float @tanhf(
x.tanh()
}

// Since we're now marked as readnone, the call to tanh can be optimized away
// CHECK-LABEL: @dce_tanh
#[no_mangle]
pub fn dce_tanh(x: f64) -> f64 {
// DEV: call double @llvm.tanh.f64
// OPT-NOT: llvm.tanh
let _ = x.tanh();
1.0
}

// Since we're now marked as speculate, we can fold the branch into a select
// CHECK-LABEL: @speculate
#[no_mangle]
pub fn speculate(x: f64, cond: bool) -> f64 {
// DEV: br i1 %cond
// OPT-NOT: br i1
// OPT: %0 = tail call double @llvm.tanh.f64(double %x)
// OPT-NEXT: %_0.sroa.0.0 = select i1 %cond, double %0, double 0.000000e+00
// OPT-NEXT: ret double %_0.sroa.0.0
if cond { x.tanh() } else { 0.0 }
}
Loading