diff --git a/src/terminator/intrinsic.rs b/src/terminator/intrinsic.rs index ab8539be315..2ee4d244053 100644 --- a/src/terminator/intrinsic.rs +++ b/src/terminator/intrinsic.rs @@ -207,14 +207,50 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { return self.eval_drop_impls(drops, span); } - "fabsf32" => { + "sinf32" | "fabsf32" | "cosf32" | + "sqrtf32" | "expf32" | "exp2f32" | + "logf32" | "log10f32" | "log2f32" | + "floorf32" | "ceilf32" | "truncf32" => { let f = self.value_to_primval(arg_vals[0], f32)?.to_f32()?; - self.write_primval(dest, PrimVal::from_f32(f.abs()), dest_ty)?; + let f = match intrinsic_name { + "sinf32" => f.sin(), + "fabsf32" => f.abs(), + "cosf32" => f.cos(), + "sqrtf32" => f.sqrt(), + "expf32" => f.exp(), + "exp2f32" => f.exp2(), + "logf32" => f.ln(), + "log10f32" => f.log10(), + "log2f32" => f.log2(), + "floorf32" => f.floor(), + "ceilf32" => f.ceil(), + "truncf32" => f.trunc(), + _ => bug!(), + }; + self.write_primval(dest, PrimVal::from_f32(f), dest_ty)?; } - "fabsf64" => { + "sinf64" | "fabsf64" | "cosf64" | + "sqrtf64" | "expf64" | "exp2f64" | + "logf64" | "log10f64" | "log2f64" | + "floorf64" | "ceilf64" | "truncf64" => { let f = self.value_to_primval(arg_vals[0], f64)?.to_f64()?; - self.write_primval(dest, PrimVal::from_f64(f.abs()), dest_ty)?; + let f = match intrinsic_name { + "sinf64" => f.sin(), + "fabsf64" => f.abs(), + "cosf64" => f.cos(), + "sqrtf64" => f.sqrt(), + "expf64" => f.exp(), + "exp2f64" => f.exp2(), + "logf64" => f.ln(), + "log10f64" => f.log10(), + "log2f64" => f.log2(), + "floorf64" => f.floor(), + "ceilf64" => f.ceil(), + "truncf64" => f.trunc(), + _ => bug!(), + }; + self.write_primval(dest, PrimVal::from_f64(f), dest_ty)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { @@ -320,6 +356,32 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.intrinsic_overflowing(mir::BinOp::Add, &args[0], &args[1], dest, dest_ty)?; } + "powf32" => { + let f = self.value_to_primval(arg_vals[0], f32)?.to_f32()?; + let f2 = self.value_to_primval(arg_vals[1], f32)?.to_f32()?; + self.write_primval(dest, PrimVal::from_f32(f.powf(f2)), dest_ty)?; + } + + "powf64" => { + let f = self.value_to_primval(arg_vals[0], f64)?.to_f64()?; + let f2 = self.value_to_primval(arg_vals[1], f64)?.to_f64()?; + self.write_primval(dest, PrimVal::from_f64(f.powf(f2)), dest_ty)?; + } + + "fmaf32" => { + let a = self.value_to_primval(arg_vals[0], f32)?.to_f32()?; + let b = self.value_to_primval(arg_vals[1], f32)?.to_f32()?; + let c = self.value_to_primval(arg_vals[2], f32)?.to_f32()?; + self.write_primval(dest, PrimVal::from_f32(a * b + c), dest_ty)?; + } + + "fmaf64" => { + let a = self.value_to_primval(arg_vals[0], f64)?.to_f64()?; + let b = self.value_to_primval(arg_vals[1], f64)?.to_f64()?; + let c = self.value_to_primval(arg_vals[2], f64)?.to_f64()?; + self.write_primval(dest, PrimVal::from_f64(a * b + c), dest_ty)?; + } + "powif32" => { let f = self.value_to_primval(arg_vals[0], f32)?.to_f32()?; let i = self.value_to_primval(arg_vals[1], i32)?.to_i128()?; @@ -332,16 +394,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { self.write_primval(dest, PrimVal::from_f64(f.powi(i as i32)), dest_ty)?; } - "sqrtf32" => { - let f = self.value_to_primval(arg_vals[0], f32)?.to_f32()?; - self.write_primval(dest, PrimVal::from_f32(f.sqrt()), dest_ty)?; - } - - "sqrtf64" => { - let f = self.value_to_primval(arg_vals[0], f64)?.to_f64()?; - self.write_primval(dest, PrimVal::from_f64(f.sqrt()), dest_ty)?; - } - "size_of" => { let ty = substs.type_at(0); // FIXME: change the `box_free` lang item to take `T: ?Sized` and have it use the diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs new file mode 100644 index 00000000000..a2c55634749 --- /dev/null +++ b/tests/run-pass/intrinsics-math.rs @@ -0,0 +1,67 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => ({ + let (a, b) = (&$a, &$b); + assert!((*a - *b).abs() < 1.0e-6, + "{} is not approximately equal to {}", *a, *b); + }) +} + +pub fn main() { + use std::f32; + use std::f64; + + assert_approx_eq!(64f32.sqrt(), 8f32); + assert_approx_eq!(64f64.sqrt(), 8f64); + + assert_approx_eq!(25f32.powi(-2), 0.0016f32); + assert_approx_eq!(23.2f64.powi(2), 538.24f64); + + assert_approx_eq!(0f32.sin(), 0f32); + assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64); + + assert_approx_eq!(0f32.cos(), 1f32); + assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64); + + assert_approx_eq!(25f32.powf(-2f32), 0.0016f32); + assert_approx_eq!(400f64.powf(0.5f64), 20f64); + + assert_approx_eq!((1f32.exp() - f32::consts::E).abs(), 0f32); + assert_approx_eq!(1f64.exp(), f64::consts::E); + + assert_approx_eq!(10f32.exp2(), 1024f32); + assert_approx_eq!(50f64.exp2(), 1125899906842624f64); + + assert_approx_eq!((f32::consts::E.ln() - 1f32).abs(), 0f32); + assert_approx_eq!(1f64.ln(), 0f64); + + assert_approx_eq!(10f32.log10(), 1f32); + assert_approx_eq!(f64::consts::E.log10(), f64::consts::LOG10_E); + + assert_approx_eq!(8f32.log2(), 3f32); + assert_approx_eq!(f64::consts::E.log2(), f64::consts::LOG2_E); + + assert_approx_eq!(1.0f32.mul_add(2.0f32, 5.0f32), 7.0f32); + assert_approx_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E); + + assert_approx_eq!((-1.0f32).abs(), 1.0f32); + assert_approx_eq!(34.2f64.abs(), 34.2f64); + + assert_approx_eq!(3.8f32.floor(), 3.0f32); + assert_approx_eq!((-1.1f64).floor(), -2.0f64); + + assert_approx_eq!((-2.3f32).ceil(), -2.0f32); + assert_approx_eq!(3.8f64.ceil(), 4.0f64); + + assert_approx_eq!(0.1f32.trunc(), 0.0f32); + assert_approx_eq!((-0.1f64).trunc(), 0.0f64); +}