diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index ea4792bb495f6..3ddf376c2aa6d 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -414,101 +414,198 @@ extern "rust-intrinsic" { pub fn volatile_store(dst: *mut T, val: T); /// Returns the square root of an `f32` + #[cfg(stage0)] pub fn sqrtf32(x: f32) -> f32; /// Returns the square root of an `f64` + #[cfg(stage0)] pub fn sqrtf64(x: f64) -> f64; + /// Returns the square root of a floating point type `T`. + #[cfg(not(stage0))] + pub fn sqrt(x: T) -> T; /// Raises an `f32` to an integer power. + #[cfg(stage0)] pub fn powif32(a: f32, x: i32) -> f32; /// Raises an `f64` to an integer power. + #[cfg(stage0)] pub fn powif64(a: f64, x: i32) -> f64; + /// Raises a floating point to an integer power. + #[cfg(not(stage0))] + pub fn powi(a: T, x: i32) -> T; /// Returns the sine of an `f32`. + #[cfg(stage0)] pub fn sinf32(x: f32) -> f32; /// Returns the sine of an `f64`. + #[cfg(stage0)] pub fn sinf64(x: f64) -> f64; + /// Returns the sine of a floating point type `T`. + #[cfg(not(stage0))] + pub fn sin(x: T) -> T; /// Returns the cosine of an `f32`. + #[cfg(stage0)] pub fn cosf32(x: f32) -> f32; /// Returns the cosine of an `f64`. + #[cfg(stage0)] pub fn cosf64(x: f64) -> f64; + /// Returns the cosine of a floating point type `T`. + #[cfg(not(stage0))] + pub fn cos(x: T) -> T; /// Raises an `f32` to an `f32` power. + #[cfg(stage0)] pub fn powf32(a: f32, x: f32) -> f32; /// Raises an `f64` to an `f64` power. + #[cfg(stage0)] pub fn powf64(a: f64, x: f64) -> f64; + /// Raises floating point of type `T` to a floating point of type `T` power. + #[cfg(not(stage0))] + pub fn pow(a: T, x: T) -> T; /// Returns the exponential of an `f32`. + #[cfg(stage0)] pub fn expf32(x: f32) -> f32; /// Returns the exponential of an `f64`. + #[cfg(stage0)] pub fn expf64(x: f64) -> f64; + /// Returns the exponential of a foating point of type `T`. + #[cfg(not(stage0))] + pub fn exp(x: T) -> T; /// Returns 2 raised to the power of an `f32`. + #[cfg(stage0)] pub fn exp2f32(x: f32) -> f32; /// Returns 2 raised to the power of an `f64`. + #[cfg(stage0)] pub fn exp2f64(x: f64) -> f64; + /// Returns 2 raised to the power of a floating point of type `T`. + #[cfg(not(stage0))] + pub fn exp2(x: T) -> T; /// Returns the natural logarithm of an `f32`. + #[cfg(stage0)] pub fn logf32(x: f32) -> f32; /// Returns the natural logarithm of an `f64`. + #[cfg(stage0)] pub fn logf64(x: f64) -> f64; + /// Returns the natural logarithm of a floating point of type `T`. + #[cfg(not(stage0))] + pub fn log(x: T) -> T; /// Returns the base 10 logarithm of an `f32`. + #[cfg(stage0)] pub fn log10f32(x: f32) -> f32; /// Returns the base 10 logarithm of an `f64`. + #[cfg(stage0)] pub fn log10f64(x: f64) -> f64; + /// Returns the base 10 logarithm of a foating point of type `T`. + #[cfg(not(stage0))] + pub fn log10(x: T) -> T; /// Returns the base 2 logarithm of an `f32`. + #[cfg(stage0)] pub fn log2f32(x: f32) -> f32; /// Returns the base 2 logarithm of an `f64`. + #[cfg(stage0)] pub fn log2f64(x: f64) -> f64; + /// Returns the base 2 logarithm of a floating point of type `T`. + #[cfg(not(stage0))] + pub fn log2(x: T) -> T; /// Returns `a * b + c` for `f32` values. + #[cfg(stage0)] pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; /// Returns `a * b + c` for `f64` values. + #[cfg(stage0)] pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; + /// Returns `a * b + c` for floating point of type `T` values. + #[cfg(not(stage0))] + pub fn fma(a: T, b: T, c: T) -> T; /// Returns the absolute value of an `f32`. + #[cfg(stage0)] pub fn fabsf32(x: f32) -> f32; /// Returns the absolute value of an `f64`. + #[cfg(stage0)] pub fn fabsf64(x: f64) -> f64; + /// Returns the absolute value of a floating point of type `T`. + #[cfg(not(stage0))] + pub fn fabs(x: T) -> T; /// Copies the sign from `y` to `x` for `f32` values. + #[cfg(stage0)] pub fn copysignf32(x: f32, y: f32) -> f32; /// Copies the sign from `y` to `x` for `f64` values. + #[cfg(stage0)] pub fn copysignf64(x: f64, y: f64) -> f64; + /// Copies the sign from `y` to `x` for floating point values of type `T. + #[cfg(not(stage0))] + pub fn copysign(x: T, y: T) -> T; /// Returns the largest integer less than or equal to an `f32`. + #[cfg(stage0)] pub fn floorf32(x: f32) -> f32; /// Returns the largest integer less than or equal to an `f64`. + #[cfg(stage0)] pub fn floorf64(x: f64) -> f64; + /// Returns the largest integer less than or equal to a floating point of type `T`. + #[cfg(not(stage0))] + pub fn floor(x: T) -> T; /// Returns the smallest integer greater than or equal to an `f32`. + #[cfg(stage0)] pub fn ceilf32(x: f32) -> f32; /// Returns the smallest integer greater than or equal to an `f64`. + #[cfg(stage0)] pub fn ceilf64(x: f64) -> f64; + /// Returns the smallest integer greater than or equal to a floating point of type `T`. + #[cfg(not(stage0))] + pub fn ceil(T: T) -> T; /// Returns the integer part of an `f32`. + #[cfg(stage0)] pub fn truncf32(x: f32) -> f32; /// Returns the integer part of an `f64`. + #[cfg(stage0)] pub fn truncf64(x: f64) -> f64; + /// Returns the integer part of an `f64`. + #[cfg(not(stage0))] + pub fn trunc(x: T) -> T; /// Returns the nearest integer to an `f32`. May raise an inexact floating-point exception /// if the argument is not an integer. + #[cfg(stage0)] pub fn rintf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. May raise an inexact floating-point exception /// if the argument is not an integer. + #[cfg(stage0)] pub fn rintf64(x: f64) -> f64; + /// Returns the nearest integer to a floating point of type `T`. May raise an inexact + /// floating-point exception if the argument is not an integer. + #[cfg(not(stage0))] + pub fn rint(x: T) -> T; /// Returns the nearest integer to an `f32`. + #[cfg(stage0)] pub fn nearbyintf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. + #[cfg(stage0)] pub fn nearbyintf64(x: f64) -> f64; + /// Returns the nearest integer to a floating point of type `T`. + #[cfg(not(stage0))] + pub fn nearbyint(x: T) -> T; /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. + #[cfg(stage0)] pub fn roundf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero. + #[cfg(stage0)] pub fn roundf64(x: f64) -> f64; + /// Returns the nearest integer to a a floating point of type `T`. + /// Rounds half-way cases away from zero. + #[cfg(not(stage0))] + pub fn round(x: T) -> T; /// Returns the number of bits set in a `u8`. #[cfg(stage0)] diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 6185823d00132..d53207cd77b19 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -219,9 +219,15 @@ impl Float for f32 { /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[inline] + #[cfg(stage0)] fn abs(self) -> f32 { unsafe { intrinsics::fabsf32(self) } } + #[inline] + #[cfg(not(stage0))] + fn abs(self) -> f32 { + unsafe { intrinsics::fabs(self) } + } /// Returns a number that represents the sign of `self`. /// @@ -229,6 +235,7 @@ impl Float for f32 { /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` /// - `Float::nan()` if the number is `Float::nan()` #[inline] + #[cfg(stage0)] fn signum(self) -> f32 { if self.is_nan() { Float::nan() @@ -236,6 +243,15 @@ impl Float for f32 { unsafe { intrinsics::copysignf32(1.0, self) } } } + #[inline] + #[cfg(not(stage0))] + fn signum(self) -> f32 { + if self.is_nan() { + Float::nan() + } else { + unsafe { intrinsics::copysign(1.0, self) } + } + } /// Returns `true` if `self` is positive, including `+0.0` and /// `Float::infinity()`. @@ -256,9 +272,15 @@ impl Float for f32 { fn recip(self) -> f32 { 1.0 / self } #[inline] + #[cfg(stage0)] fn powi(self, n: i32) -> f32 { unsafe { intrinsics::powif32(self, n) } } + #[inline] + #[cfg(not(stage0))] + fn powi(self, n: i32) -> f32 { + unsafe { intrinsics::powi(self, n) } + } /// Converts to degrees, assuming the number is in radians. #[inline] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index f85f8c5bd1433..8c7dd14d739ff 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -219,9 +219,15 @@ impl Float for f64 { /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[inline] + #[cfg(stage0)] fn abs(self) -> f64 { unsafe { intrinsics::fabsf64(self) } } + #[inline] + #[cfg(not(stage0))] + fn abs(self) -> f64 { + unsafe { intrinsics::fabs(self) } + } /// Returns a number that represents the sign of `self`. /// @@ -229,6 +235,7 @@ impl Float for f64 { /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` /// - `Float::nan()` if the number is `Float::nan()` #[inline] + #[cfg(stage0)] fn signum(self) -> f64 { if self.is_nan() { Float::nan() @@ -236,6 +243,15 @@ impl Float for f64 { unsafe { intrinsics::copysignf64(1.0, self) } } } + #[inline] + #[cfg(not(stage0))] + fn signum(self) -> f64 { + if self.is_nan() { + Float::nan() + } else { + unsafe { intrinsics::copysign(1.0, self) } + } + } /// Returns `true` if `self` is positive, including `+0.0` and /// `Float::infinity()`. @@ -256,9 +272,15 @@ impl Float for f64 { fn recip(self) -> f64 { 1.0 / self } #[inline] + #[cfg(stage0)] fn powi(self, n: i32) -> f64 { unsafe { intrinsics::powif64(self, n) } } + #[inline] + #[cfg(not(stage0))] + fn powi(self, n: i32) -> f64 { + unsafe { intrinsics::powi(self, n) } + } /// Converts to degrees, assuming the number is in radians. #[inline] diff --git a/src/librand/lib.rs b/src/librand/lib.rs index b5a1eb9520cec..50119b90d3426 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -82,21 +82,40 @@ trait FloatMath : Sized { impl FloatMath for f64 { #[inline] + #[cfg(stage0)] fn exp(self) -> f64 { unsafe { intrinsics::expf64(self) } } + #[inline] + #[cfg(not(stage0))] + fn exp(self) -> f64 { + unsafe { intrinsics::exp(self) } + } #[inline] + #[cfg(stage0)] fn ln(self) -> f64 { unsafe { intrinsics::logf64(self) } } + #[inline] + #[cfg(not(stage0))] + fn ln(self) -> f64 { + unsafe { intrinsics::log(self) } + } #[inline] + #[cfg(stage0)] fn powf(self, n: f64) -> f64 { unsafe { intrinsics::powf64(self, n) } } + #[inline] + #[cfg(not(stage0))] + fn powf(self, n: f64) -> f64 { + unsafe { intrinsics::pow(self, n) } + } #[inline] + #[cfg(stage0)] fn sqrt(self) -> f64 { if self < 0.0 { f64::NAN @@ -104,6 +123,15 @@ impl FloatMath for f64 { unsafe { intrinsics::sqrtf64(self) } } } + #[inline] + #[cfg(not(stage0))] + fn sqrt(self) -> f64 { + if self < 0.0 { + f64::NAN + } else { + unsafe { intrinsics::sqrt(self) } + } + } } /// A type that can be randomly generated using an `Rng`. diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 773256a17e4ac..2009f186bd09d 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -49,52 +49,6 @@ use syntax::codemap::Span; use std::cmp::Ordering; -pub fn get_simple_intrinsic(ccx: &CrateContext, item: &hir::ForeignItem) -> Option { - let name = match &*item.name.as_str() { - "sqrtf32" => "llvm.sqrt.f32", - "sqrtf64" => "llvm.sqrt.f64", - "powif32" => "llvm.powi.f32", - "powif64" => "llvm.powi.f64", - "sinf32" => "llvm.sin.f32", - "sinf64" => "llvm.sin.f64", - "cosf32" => "llvm.cos.f32", - "cosf64" => "llvm.cos.f64", - "powf32" => "llvm.pow.f32", - "powf64" => "llvm.pow.f64", - "expf32" => "llvm.exp.f32", - "expf64" => "llvm.exp.f64", - "exp2f32" => "llvm.exp2.f32", - "exp2f64" => "llvm.exp2.f64", - "logf32" => "llvm.log.f32", - "logf64" => "llvm.log.f64", - "log10f32" => "llvm.log10.f32", - "log10f64" => "llvm.log10.f64", - "log2f32" => "llvm.log2.f32", - "log2f64" => "llvm.log2.f64", - "fmaf32" => "llvm.fma.f32", - "fmaf64" => "llvm.fma.f64", - "fabsf32" => "llvm.fabs.f32", - "fabsf64" => "llvm.fabs.f64", - "copysignf32" => "llvm.copysign.f32", - "copysignf64" => "llvm.copysign.f64", - "floorf32" => "llvm.floor.f32", - "floorf64" => "llvm.floor.f64", - "ceilf32" => "llvm.ceil.f32", - "ceilf64" => "llvm.ceil.f64", - "truncf32" => "llvm.trunc.f32", - "truncf64" => "llvm.trunc.f64", - "rintf32" => "llvm.rint.f32", - "rintf64" => "llvm.rint.f64", - "nearbyintf32" => "llvm.nearbyint.f32", - "nearbyintf64" => "llvm.nearbyint.f64", - "roundf32" => "llvm.round.f32", - "roundf64" => "llvm.round.f64", - "assume" => "llvm.assume", - _ => return None - }; - Some(ccx.get_intrinsic(&name)) -} - pub fn span_transmute_size_error(a: &Session, b: Span, msg: &str) { span_err!(a, b, E0512, "{}", msg); } @@ -402,21 +356,22 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } }; - let simple = get_simple_intrinsic(ccx, &*foreign_item); - let llval = match (simple, &*name) { - (Some(llfn), _) => { + let llval = match &*name { + + "assume" => { + let llfn = ccx.get_intrinsic(&("llvm.assume")); Call(bcx, llfn, &llargs, None, call_debug_location) } - (_, "breakpoint") => { + "breakpoint" => { let llfn = ccx.get_intrinsic(&("llvm.debugtrap")); Call(bcx, llfn, &[], None, call_debug_location) } - (_, "size_of") => { + "size_of" => { let tp_ty = *substs.types.get(FnSpace, 0); let lltp_ty = type_of::type_of(ccx, tp_ty); C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) } - (_, "size_of_val") => { + "size_of_val" => { let tp_ty = *substs.types.get(FnSpace, 0); if !type_is_sized(tcx, tp_ty) { let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]); @@ -426,11 +381,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty)) } } - (_, "min_align_of") => { + "min_align_of" => { let tp_ty = *substs.types.get(FnSpace, 0); C_uint(ccx, type_of::align_of(ccx, tp_ty)) } - (_, "min_align_of_val") => { + "min_align_of_val" => { let tp_ty = *substs.types.get(FnSpace, 0); if !type_is_sized(tcx, tp_ty) { let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]); @@ -439,12 +394,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, C_uint(ccx, type_of::align_of(ccx, tp_ty)) } } - (_, "pref_align_of") => { + "pref_align_of" => { let tp_ty = *substs.types.get(FnSpace, 0); let lltp_ty = type_of::type_of(ccx, tp_ty); C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty)) } - (_, "drop_in_place") => { + "drop_in_place" => { let tp_ty = *substs.types.get(FnSpace, 0); let ptr = if type_is_sized(tcx, tp_ty) { llargs[0] @@ -458,24 +413,24 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, glue::drop_ty(bcx, ptr, tp_ty, call_debug_location); C_nil(ccx) } - (_, "type_name") => { + "type_name" => { let tp_ty = *substs.types.get(FnSpace, 0); let ty_name = token::intern_and_get_ident(&tp_ty.to_string()); C_str_slice(ccx, ty_name) } - (_, "type_id") => { + "type_id" => { let hash = ccx.tcx().hash_crate_independent(*substs.types.get(FnSpace, 0), &ccx.link_meta().crate_hash); C_u64(ccx, hash) } - (_, "init_dropped") => { + "init_dropped" => { let tp_ty = *substs.types.get(FnSpace, 0); if !return_type_is_void(ccx, tp_ty) { drop_done_fill_mem(bcx, llresult, tp_ty); } C_nil(ccx) } - (_, "init") => { + "init" => { let tp_ty = *substs.types.get(FnSpace, 0); if !return_type_is_void(ccx, tp_ty) { // Just zero out the stack slot. (See comment on base::memzero for explanation) @@ -484,26 +439,26 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, C_nil(ccx) } // Effectively no-ops - (_, "uninit") | (_, "forget") => { + "uninit" | "forget" => { C_nil(ccx) } - (_, "needs_drop") => { + "needs_drop" => { let tp_ty = *substs.types.get(FnSpace, 0); C_bool(ccx, bcx.fcx.type_needs_drop(tp_ty)) } - (_, "offset") => { + "offset" => { let ptr = llargs[0]; let offset = llargs[1]; InBoundsGEP(bcx, ptr, &[offset]) } - (_, "arith_offset") => { + "arith_offset" => { let ptr = llargs[0]; let offset = llargs[1]; GEP(bcx, ptr, &[offset]) } - (_, "copy_nonoverlapping") => { + "copy_nonoverlapping" => { copy_intrinsic(bcx, false, false, @@ -513,7 +468,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, llargs[2], call_debug_location) } - (_, "copy") => { + "copy" => { copy_intrinsic(bcx, true, false, @@ -523,7 +478,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, llargs[2], call_debug_location) } - (_, "write_bytes") => { + "write_bytes" => { memset_intrinsic(bcx, false, *substs.types.get(FnSpace, 0), @@ -533,7 +488,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, call_debug_location) } - (_, "volatile_copy_nonoverlapping_memory") => { + "volatile_copy_nonoverlapping_memory" => { copy_intrinsic(bcx, false, true, @@ -543,7 +498,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, llargs[2], call_debug_location) } - (_, "volatile_copy_memory") => { + "volatile_copy_memory" => { copy_intrinsic(bcx, true, true, @@ -553,7 +508,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, llargs[2], call_debug_location) } - (_, "volatile_set_memory") => { + "volatile_set_memory" => { memset_intrinsic(bcx, true, *substs.types.get(FnSpace, 0), @@ -562,7 +517,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, llargs[2], call_debug_location) } - (_, "volatile_load") => { + "volatile_load" => { let tp_ty = *substs.types.get(FnSpace, 0); let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty); let load = VolatileLoad(bcx, ptr); @@ -571,7 +526,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } to_arg_ty(bcx, load, tp_ty) }, - (_, "volatile_store") => { + "volatile_store" => { let tp_ty = *substs.types.get(FnSpace, 0); let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty); let val = from_arg_ty(bcx, llargs[1], tp_ty); @@ -582,10 +537,47 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, C_nil(ccx) }, - (_, "ctlz") | (_, "cttz") | (_, "ctpop") | (_, "bswap") | - (_, "add_with_overflow") | (_, "sub_with_overflow") | (_, "mul_with_overflow") | - (_, "overflowing_add") | (_, "overflowing_sub") | (_, "overflowing_mul") | - (_, "unchecked_div") | (_, "unchecked_rem") => { + "sqrt" | + "powi" | + "sin" | + "cos" | + "pow" | + "exp" | + "exp2" | + "log" | + "log10" | + "log2" | + "fma" | + "fabs" | + "copysign" | + "floor" | + "ceil" | + "trunc" | + "rint" | + "nearbyint"| + "round" => { + use rustc::middle::ty::{TyFloat}; + let sty = &arg_tys[0].sty; + if let &TyFloat(t) = sty { + let width = match t { + ast::TyF32 => 32, + ast::TyF64 => 64, + }; + Call(bcx, ccx.get_intrinsic(&format!("llvm.{}.f{}", name, width)), + &llargs, None, call_debug_location) + } else { + span_invalid_monomorphization_error(tcx.sess, call_info.span, + &format!("invalid monomorphization of `{}` intrinsic: \ + expected basic floating point type, found `{}`,", + name, sty)); + C_null(llret_ty) + } + }, + + "ctlz" | "cttz" | "ctpop" | "bswap" | + "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" | + "overflowing_add" | "overflowing_sub" | "overflowing_mul" | + "unchecked_div" | "unchecked_rem" => { let sty = &arg_tys[0].sty; match int_type_width_signed(sty, ccx) { Some((width, signed)) => @@ -638,9 +630,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } }, - - - (_, "return_address") => { + "return_address" => { if !fcx.caller_expects_out_pointer { span_err!(tcx.sess, call_info.span, E0510, "invalid use of `return_address` intrinsic: function \ @@ -649,9 +639,9 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } else { PointerCast(bcx, llvm::get_param(fcx.llfn, 0), Type::i8p(ccx)) } - } + }, - (_, "discriminant_value") => { + "discriminant_value" => { let val_ty = substs.types.get(FnSpace, 0); match val_ty.sty { ty::TyEnum(..) => { @@ -660,8 +650,9 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } _ => C_null(llret_ty) } - } - (_, name) if name.starts_with("simd_") => { + }, + + name if name.starts_with("simd_") => { generic_simd_intrinsic(bcx, name, substs, callee_ty, @@ -673,7 +664,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } // This requires that atomic intrinsics follow a specific naming pattern: // "atomic_[_]", and no ordering means SeqCst - (_, name) if name.starts_with("atomic_") => { + name if name.starts_with("atomic_") => { let split: Vec<&str> = name.split('_').collect(); assert!(split.len() >= 2, "Atomic intrinsic not correct format"); @@ -764,10 +755,9 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, AtomicRMW(bcx, atom_op, ptr, val, order) } } - } - (_, _) => { + _ => { let intr = match Intrinsic::find(tcx, &name) { Some(intr) => intr, None => ccx.sess().span_bug(foreign_item.span, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 0ab0f1f9c1de1..a217d26f48444 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -192,68 +192,18 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { ), tcx.mk_nil()) } - "sqrtf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "sqrtf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "powif32" => { - (0, - vec!( tcx.types.f32, tcx.types.i32 ), - tcx.types.f32) - } - "powif64" => { - (0, - vec!( tcx.types.f64, tcx.types.i32 ), - tcx.types.f64) - } - "sinf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "sinf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "cosf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "cosf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "powf32" => { - (0, - vec!( tcx.types.f32, tcx.types.f32 ), - tcx.types.f32) - } - "powf64" => { - (0, - vec!( tcx.types.f64, tcx.types.f64 ), - tcx.types.f64) - } - "expf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "expf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "exp2f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "exp2f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "logf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "logf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "log10f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "log10f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "log2f32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "log2f64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "fmaf32" => { - (0, - vec!( tcx.types.f32, tcx.types.f32, tcx.types.f32 ), - tcx.types.f32) - } - "fmaf64" => { - (0, - vec!( tcx.types.f64, tcx.types.f64, tcx.types.f64 ), - tcx.types.f64) - } - "fabsf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "fabsf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "copysignf32" => (0, vec!( tcx.types.f32, tcx.types.f32 ), tcx.types.f32), - "copysignf64" => (0, vec!( tcx.types.f64, tcx.types.f64 ), tcx.types.f64), - "floorf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "floorf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "ceilf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "ceilf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "truncf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "truncf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "rintf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "rintf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "nearbyintf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "nearbyintf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), - "roundf32" => (0, vec!( tcx.types.f32 ), tcx.types.f32), - "roundf64" => (0, vec!( tcx.types.f64 ), tcx.types.f64), + "sqrt" | "sin" | "cos" | "exp" | "exp2" | "log" | "log10" | "log2" | "fabs" | + "floor" | "ceil" | "trunc" | "rint" | "nearbyint" | "round" => + (1, vec!(param(ccx, 0)), param(ccx, 0)), + + "powi" => + (1, vec!(param(ccx, 0), tcx.types.i32), param(ccx, 0)), + + "pow" | "copysign" => + (1, vec!(param(ccx, 0), param(ccx, 0)), param(ccx, 0)), + + "fma" => + (1, vec!(param(ccx, 0), param(ccx, 0), param(ccx, 0)), param(ccx, 0)), "volatile_load" => (1, vec!( tcx.mk_imm_ptr(param(ccx, 0)) ), param(ccx, 0)), diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index a04dfbeebe8e6..6879309667cad 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -289,8 +289,10 @@ impl f32 { // function on MSVC, but there are many others elsewhere. #[cfg(target_env = "msvc")] fn floorf(f: f32) -> f32 { (f as f64).floor() as f32 } - #[cfg(not(target_env = "msvc"))] + #[cfg(all(not(target_env = "msvc"), stage0))] fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } } + #[cfg(all(not(target_env = "msvc"), not(stage0)))] + fn floorf(f: f32) -> f32 { unsafe { intrinsics::floor(f) } } } /// Returns the smallest integer greater than or equal to a number. @@ -304,6 +306,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn ceil(self) -> f32 { return ceilf(self); @@ -314,6 +317,18 @@ impl f32 { fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceilf32(f) } } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn ceil(self) -> f32 { + return ceilf(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn ceilf(f: f32) -> f32 { (f as f64).ceil() as f32 } + #[cfg(not(target_env = "msvc"))] + fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceil(f) } } + } /// Returns the nearest integer to a number. Round half-way cases away from /// `0.0`. /// @@ -326,9 +341,16 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn round(self) -> f32 { unsafe { intrinsics::roundf32(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn round(self) -> f32 { + unsafe { intrinsics::round(self) } + } /// Returns the integer part of a number. /// @@ -341,9 +363,16 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn trunc(self) -> f32 { unsafe { intrinsics::truncf32(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn trunc(self) -> f32 { + unsafe { intrinsics::trunc(self) } + } /// Returns the fractional part of a number. /// @@ -459,9 +488,16 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn mul_add(self, a: f32, b: f32) -> f32 { unsafe { intrinsics::fmaf32(self, a, b) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn mul_add(self, a: f32, b: f32) -> f32 { + unsafe { intrinsics::fma(self, a, b) } + } /// Takes the reciprocal (inverse) of a number, `1/x`. /// @@ -505,6 +541,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn powf(self, n: f32) -> f32 { return powf(self, n); @@ -515,6 +552,19 @@ impl f32 { fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::powf32(f, n) } } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn powf(self, n: f32) -> f32 { + return powf(self, n); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn powf(f: f32, n: f32) -> f32 { (f as f64).powf(n as f64) as f32 } + #[cfg(not(target_env = "msvc"))] + fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::pow(f, n) } } + } + /// Takes the square root of a number. /// /// Returns NaN if `self` is a negative number. @@ -532,6 +582,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn sqrt(self) -> f32 { if self < 0.0 { NAN @@ -539,6 +590,16 @@ impl f32 { unsafe { intrinsics::sqrtf32(self) } } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn sqrt(self) -> f32 { + if self < 0.0 { + NAN + } else { + unsafe { intrinsics::sqrt(self) } + } + } /// Returns `e^(self)`, (the exponential function). /// @@ -556,6 +617,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn exp(self) -> f32 { return expf(self); @@ -566,6 +628,18 @@ impl f32 { fn expf(f: f32) -> f32 { unsafe { intrinsics::expf32(f) } } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn exp(self) -> f32 { + return expf(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn expf(f: f32) -> f32 { (f as f64).exp() as f32 } + #[cfg(not(target_env = "msvc"))] + fn expf(f: f32) -> f32 { unsafe { intrinsics::exp(f) } } + } /// Returns `2^(self)`. /// /// ``` @@ -580,9 +654,16 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn exp2(self) -> f32 { unsafe { intrinsics::exp2f32(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn exp2(self) -> f32 { + unsafe { intrinsics::exp2(self) } + } /// Returns the natural logarithm of the number. /// @@ -600,6 +681,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn ln(self) -> f32 { return logf(self); @@ -610,6 +692,19 @@ impl f32 { fn logf(f: f32) -> f32 { unsafe { intrinsics::logf32(f) } } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn ln(self) -> f32 { + return logf(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn logf(f: f32) -> f32 { (f as f64).ln() as f32 } + #[cfg(not(target_env = "msvc"))] + fn logf(f: f32) -> f32 { unsafe { intrinsics::log(f) } } + } + /// Returns the logarithm of the number with respect to an arbitrary base. /// /// ``` @@ -645,9 +740,16 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn log2(self) -> f32 { unsafe { intrinsics::log2f32(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn log2(self) -> f32 { + unsafe { intrinsics::log2(self) } + } /// Returns the base 10 logarithm of the number. /// @@ -663,6 +765,7 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn log10(self) -> f32 { return log10f(self); @@ -673,6 +776,19 @@ impl f32 { fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10f32(f) } } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn log10(self) -> f32 { + return log10f(self); + + // see notes above in `floor` + #[cfg(target_env = "msvc")] + fn log10f(f: f32) -> f32 { (f as f64).log10() as f32 } + #[cfg(not(target_env = "msvc"))] + fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10(f) } } + } + /// Converts radians to degrees. /// /// ``` @@ -895,8 +1011,10 @@ impl f32 { // see notes in `core::f32::Float::floor` #[cfg(target_env = "msvc")] fn sinf(f: f32) -> f32 { (f as f64).sin() as f32 } - #[cfg(not(target_env = "msvc"))] + #[cfg(all(not(target_env = "msvc"), stage0))] fn sinf(f: f32) -> f32 { unsafe { intrinsics::sinf32(f) } } + #[cfg(all(not(target_env = "msvc"), not(stage0)))] + fn sinf(f: f32) -> f32 { unsafe { intrinsics::sin(f) } } } /// Computes the cosine of a number (in radians). @@ -918,8 +1036,10 @@ impl f32 { // see notes in `core::f32::Float::floor` #[cfg(target_env = "msvc")] fn cosf(f: f32) -> f32 { (f as f64).cos() as f32 } - #[cfg(not(target_env = "msvc"))] + #[cfg(all(not(target_env = "msvc"), stage0))] fn cosf(f: f32) -> f32 { unsafe { intrinsics::cosf32(f) } } + #[cfg(all(not(target_env = "msvc"), not(stage0)))] + fn cosf(f: f32) -> f32 { unsafe { intrinsics::cos(f) } } } /// Computes the tangent of a number (in radians). diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 329d3329be649..71d814fabb9f5 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -224,9 +224,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn floor(self) -> f64 { unsafe { intrinsics::floorf64(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn floor(self) -> f64 { + unsafe { intrinsics::floor(self) } + } /// Returns the smallest integer greater than or equal to a number. /// @@ -239,9 +246,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn ceil(self) -> f64 { unsafe { intrinsics::ceilf64(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn ceil(self) -> f64 { + unsafe { intrinsics::ceil(self) } + } /// Returns the nearest integer to a number. Round half-way cases away from /// `0.0`. @@ -255,9 +269,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn round(self) -> f64 { unsafe { intrinsics::roundf64(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn round(self) -> f64 { + unsafe { intrinsics::round(self) } + } /// Returns the integer part of a number. /// @@ -270,9 +291,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn trunc(self) -> f64 { unsafe { intrinsics::truncf64(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn trunc(self) -> f64 { + unsafe { intrinsics::trunc(self) } + } /// Returns the fractional part of a number. /// @@ -396,9 +424,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn mul_add(self, a: f64, b: f64) -> f64 { unsafe { intrinsics::fmaf64(self, a, b) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn mul_add(self, a: f64, b: f64) -> f64 { + unsafe { intrinsics::fma(self, a, b) } + } /// Takes the reciprocal (inverse) of a number, `1/x`. /// @@ -436,9 +471,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn powf(self, n: f64) -> f64 { unsafe { intrinsics::powf64(self, n) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn powf(self, n: f64) -> f64 { + unsafe { intrinsics::pow(self, n) } + } /// Takes the square root of a number. /// @@ -455,6 +497,7 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn sqrt(self) -> f64 { if self < 0.0 { NAN @@ -462,6 +505,16 @@ impl f64 { unsafe { intrinsics::sqrtf64(self) } } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn sqrt(self) -> f64 { + if self < 0.0 { + NAN + } else { + unsafe { intrinsics::sqrt(self) } + } + } /// Returns `e^(self)`, (the exponential function). /// @@ -477,9 +530,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn exp(self) -> f64 { unsafe { intrinsics::expf64(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn exp(self) -> f64 { + unsafe { intrinsics::exp(self) } + } /// Returns `2^(self)`. /// @@ -493,9 +553,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn exp2(self) -> f64 { unsafe { intrinsics::exp2f64(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn exp2(self) -> f64 { + unsafe { intrinsics::exp2(self) } + } /// Returns the natural logarithm of the number. /// @@ -511,9 +578,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn ln(self) -> f64 { unsafe { intrinsics::logf64(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn ln(self) -> f64 { + unsafe { intrinsics::log(self) } + } /// Returns the logarithm of the number with respect to an arbitrary base. /// @@ -546,9 +620,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn log2(self) -> f64 { unsafe { intrinsics::log2f64(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn log2(self) -> f64 { + unsafe { intrinsics::log2(self) } + } /// Returns the base 10 logarithm of the number. /// @@ -562,9 +643,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn log10(self) -> f64 { unsafe { intrinsics::log10f64(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn log10(self) -> f64 { + unsafe { intrinsics::log10(self) } + } /// Converts radians to degrees. /// @@ -765,9 +853,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn sin(self) -> f64 { unsafe { intrinsics::sinf64(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn sin(self) -> f64 { + unsafe { intrinsics::sin(self) } + } /// Computes the cosine of a number (in radians). /// @@ -782,9 +877,16 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] + #[cfg(stage0)] pub fn cos(self) -> f64 { unsafe { intrinsics::cosf64(self) } } + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[cfg(not(stage0))] + pub fn cos(self) -> f64 { + unsafe { intrinsics::cos(self) } + } /// Computes the tangent of a number (in radians). /// diff --git a/src/test/codegen/intrinsic-no-unnamed-attr.rs b/src/test/codegen/intrinsic-no-unnamed-attr.rs index 0f239c8426575..b912b24b4609c 100644 --- a/src/test/codegen/intrinsic-no-unnamed-attr.rs +++ b/src/test/codegen/intrinsic-no-unnamed-attr.rs @@ -13,10 +13,19 @@ #![feature(intrinsics)] extern "rust-intrinsic" { + #[cfg(stage0)] fn sqrtf32(x: f32) -> f32; + #[cfg(not(stage0))] + fn sqrt(x: T) -> T; } // CHECK: @llvm.sqrt.f32(float) #{{[0-9]*}} +#[cfg(stage0)] fn main() { unsafe { sqrtf32(0.0f32); } } + +#[cfg(not(stage0))] +fn main() { + unsafe { sqrtf(0.0f32); } +} diff --git a/src/test/run-pass/intrinsics-math.rs b/src/test/run-pass/intrinsics-math.rs index f547519b671f1..fb7d75b20bbdb 100644 --- a/src/test/run-pass/intrinsics-math.rs +++ b/src/test/run-pass/intrinsics-math.rs @@ -21,39 +21,100 @@ macro_rules! assert_approx_eq { mod rusti { extern "rust-intrinsic" { + #[cfg(stage0)] pub fn sqrtf32(x: f32) -> f32; + #[cfg(stage0)] pub fn sqrtf64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn sqrt(x: T) -> T; + #[cfg(stage0)] pub fn powif32(a: f32, x: i32) -> f32; + #[cfg(stage0)] pub fn powif64(a: f64, x: i32) -> f64; + #[cfg(not(stage0))] + pub fn powi(a: T, x: i32) -> T; + #[cfg(stage0)] pub fn sinf32(x: f32) -> f32; + #[cfg(stage0)] pub fn sinf64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn sin(x: T) -> T; + #[cfg(stage0)] pub fn cosf32(x: f32) -> f32; + #[cfg(stage0)] pub fn cosf64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn cos(x: T) -> T; + #[cfg(stage0)] pub fn powf32(a: f32, x: f32) -> f32; + #[cfg(stage0)] pub fn powf64(a: f64, x: f64) -> f64; + #[cfg(not(stage0))] + pub fn pow(a: T, x: T) -> T; + #[cfg(stage0)] pub fn expf32(x: f32) -> f32; + #[cfg(stage0)] pub fn expf64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn exp(x: T) -> T; + #[cfg(stage0)] pub fn exp2f32(x: f32) -> f32; + #[cfg(stage0)] pub fn exp2f64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn exp2(x: T) -> T; + #[cfg(stage0)] pub fn logf32(x: f32) -> f32; + #[cfg(stage0)] pub fn logf64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn log(x: T) -> T; + #[cfg(stage0)] pub fn log10f32(x: f32) -> f32; + #[cfg(stage0)] pub fn log10f64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn log10(x: T) -> T; + #[cfg(stage0)] pub fn log2f32(x: f32) -> f32; + #[cfg(stage0)] pub fn log2f64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn log2(x: T) -> T; + #[cfg(stage0)] pub fn fmaf32(a: f32, b: f32, c: f32) -> f32; + #[cfg(stage0)] pub fn fmaf64(a: f64, b: f64, c: f64) -> f64; + #[cfg(not(stage0))] + pub fn fma(a: T, b: T, c: T) -> T; + #[cfg(stage0)] pub fn fabsf32(x: f32) -> f32; + #[cfg(stage0)] pub fn fabsf64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn fabs(x: T) -> T; + #[cfg(stage0)] pub fn floorf32(x: f32) -> f32; + #[cfg(stage0)] pub fn floorf64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn floor(x: T) -> T; + #[cfg(stage0)] pub fn ceilf32(x: f32) -> f32; + #[cfg(stage0)] pub fn ceilf64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn ceil(x: T) -> T; + #[cfg(stage0)] pub fn truncf32(x: f32) -> f32; + #[cfg(stage0)] pub fn truncf64(x: f64) -> f64; + #[cfg(not(stage0))] + pub fn trunc(x: T) -> T; } } +#[cfg(stage0)] pub fn main() { unsafe { use rusti::*; @@ -110,5 +171,64 @@ pub fn main() { //assert_eq!(truncf32(0.1f32), 0.0f32); //assert_eq!(truncf64(-0.1f64), 0.0f64); } +} + +#[cfg(not(stage0))] +pub fn main() { + unsafe { + use rusti::*; + + use std::f32; + use std::f64; + + assert_approx_eq!(sqrt(64f32), 8f32); + assert_approx_eq!(sqrt(64f64), 8f64); + + assert_approx_eq!(powi(25f32, -2), 0.0016f32); + assert_approx_eq!(powi(23.2f64, 2), 538.24f64); + + assert_approx_eq!(sin(0f32), 0f32); + assert_approx_eq!(sin(f64::consts::PI / 2f64), 1f64); + + assert_approx_eq!(cos(0f32), 1f32); + assert_approx_eq!(cos(f64::consts::PI * 2f64), 1f64); + + assert_approx_eq!(pow(25f32, -2f32), 0.0016f32); + assert_approx_eq!(pow(400f64, 0.5f64), 20f64); + + assert_approx_eq!(fabs(exp(1f32) - f32::consts::E), 0f32); + assert_approx_eq!(exp(1f64), f64::consts::E); + + assert_approx_eq!(exp2(10f32), 1024f32); + assert_approx_eq!(exp2(50f64), 1125899906842624f64); + + assert_approx_eq!(fabs(log(f32::consts::E) - 1f32), 0f32); + assert_approx_eq!(log(1f64), 0f64); + + assert_approx_eq!(log10(10f32), 1f32); + assert_approx_eq!(log10(f64::consts::E), f64::consts::LOG10_E); + + assert_approx_eq!(log2(8f32), 3f32); + assert_approx_eq!(log2(f64::consts::E), f64::consts::LOG2_E); + + assert_approx_eq!(fma(1.0f32, 2.0f32, 5.0f32), 7.0f32); + assert_approx_eq!(fma(0.0f64, -2.0f64, f64::consts::E), f64::consts::E); + + assert_approx_eq!(fabs(-1.0f32), 1.0f32); + assert_approx_eq!(fabs(34.2f64), 34.2f64); + + assert_approx_eq!(floor(3.8f32), 3.0f32); + assert_approx_eq!(floor(-1.1f64), -2.0f64); + + // Causes linker error + // undefined reference to llvm.ceil.f32/64 + //assert_eq!(ceil(-2.3f32), -2.0f32); + //assert_eq!(ceil(3.8f64), 4.0f64); + + // Causes linker error + // undefined reference to llvm.trunc.f32/64 + //assert_eq!(trunc(0.1f32), 0.0f32); + //assert_eq!(trunc(-0.1f64), 0.0f64); + } }