diff --git a/gcc-test-backend/src/main.rs b/gcc-test-backend/src/main.rs index a5a28cb88a6..234c9563246 100644 --- a/gcc-test-backend/src/main.rs +++ b/gcc-test-backend/src/main.rs @@ -1,3 +1,5 @@ +#![feature(core_intrinsics)] + fn i128_to_u64(u: i128) -> Option { let min = u64::MIN as i128; //let max = u64::MAX as i128; @@ -16,7 +18,129 @@ fn i128_to_u64(u: i128) -> Option { } fn main() { - use std::convert::TryFrom; + /*test_float!(f64, f64, f64::INFINITY, f64::NEG_INFINITY, f64::NAN); + ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => {*/ + + /*assert_eq!((0.0 as f64).min(0.0), 0.0); + assert!((0.0 as f64).min(0.0).is_sign_positive()); + assert_eq!((-0.0 as f64).min(-0.0), -0.0); + assert!((-0.0 as f64).min(-0.0).is_sign_negative()); + assert_eq!((9.0 as f64).min(9.0), 9.0); + assert_eq!((-9.0 as f64).min(0.0), -9.0); + assert_eq!((0.0 as f64).min(9.0), 0.0); + assert!((0.0 as f64).min(9.0).is_sign_positive()); + assert_eq!((-0.0 as f64).min(9.0), -0.0); + assert!((-0.0 as f64).min(9.0).is_sign_negative());*/ + + //println!("{}", 9); + //println!("{}", 9.0_f32); + //assert_eq!(-9.0_f32, -9 as f32); + + //assert_eq!("1", format!("{:.0}", 1.0f64)); + //assert_eq!("9", format!("{:.0}", 9.4f64)); + //assert_eq!("10", format!("{:.0}", 9.9f64)); + //assert_eq!("9.8", format!("{:.1}", 9.849f64)); + //assert_eq!("9.9", format!("{:.1}", 9.851f64)); + //assert_eq!("1", format!("{:.0}", 0.5f64)); + + //assert_eq!(2.3f32.copysign(-1.0), -2.3f32); + /*let f = 9.4f32; + println!("{}", f);*/ + //println!("{}", 9.4f32); // FIXME: this is using bytes_in_context(), but gives a wrong value. + + /*extern { + //pub fn printf(format: *const i8, ...) -> i32; + pub fn printf(format: *const i8, arg: f64) -> i32; + } + + unsafe { + printf(b"Num: %f\n\0" as *const _ as *const _, 9.4f64); + } + println!("{}", 9.4f64);*/ + + let mut value = 0; + let res = unsafe { std::intrinsics::atomic_cxchg(&mut value, 0, 1) }; + println!("{:?}", res); + let res = unsafe { std::intrinsics::atomic_cxchg(&mut value, 0, 1) }; + println!("{:?}", res); + + use std::sync::atomic::{AtomicBool, Ordering}; + + let a = AtomicBool::new(false); + assert_eq!(a.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst), Ok(false)); + assert_eq!(a.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst), Err(true)); + + a.store(false, Ordering::SeqCst); + assert_eq!(a.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst), Ok(false)); + + // FIXME: the code seems to be the same when using an integer, but somehow, it doesn't work for + // a float. Could it be related to the fact that floating-points use different registers? + + /*let f = 1234567.89f64; + assert_eq!("1.23456789e6", format!("{:e}", f)); + println!("{:e}", f); + println!("{:e}", 1234567.89f64);*/ + //assert_eq!("1.23456789e6", format!("{:e}", 1234567.89f64)); + /*assert_eq!("1.23456789e3", format!("{:e}", 1234.56789f64)); + assert_eq!("1.23456789E6", format!("{:E}", 1234567.89f64)); + assert_eq!("1.23456789E3", format!("{:E}", 1234.56789f64)); + assert_eq!("0.0", format!("{:?}", 0.0f64)); + assert_eq!("1.01", format!("{:?}", 1.01f64));*/ + + /*assert_eq!((-0.0 as f64).min(-9.0), -9.0); + assert_eq!((f64::INFINITY as f64).min(9.0), 9.0); + assert_eq!((9.0 as f64).min(f64::INFINITY), 9.0); + assert_eq!((f64::INFINITY as f64).min(-9.0), -9.0); + assert_eq!((-9.0 as f64).min(f64::INFINITY), -9.0); + assert_eq!((f64::NEG_INFINITY as f64).min(9.0), f64::NEG_INFINITY); + assert_eq!((9.0 as f64).min(f64::NEG_INFINITY), f64::NEG_INFINITY); + assert_eq!((f64::NEG_INFINITY as f64).min(-9.0), f64::NEG_INFINITY); + assert_eq!((-9.0 as f64).min(f64::NEG_INFINITY), f64::NEG_INFINITY);*/ + // Cranelift fmin has NaN propagation + //assert_eq!((f64::NAN as f64).min(9.0), 9.0); + //assert_eq!((f64::NAN as f64).min(-9.0), -9.0); + //assert_eq!((9.0 as f64).min(f64::NAN), 9.0); + //assert_eq!((-9.0 as f64).min(f64::NAN), -9.0); + //assert!((f64::NAN as f64).min(f64::NAN).is_nan()); + + /*let max: f64 = f32::MAX.into(); + assert_eq!(max as f32, f32::MAX); + assert!(max.is_normal()); + + let min: f64 = f32::MIN.into(); + assert_eq!(min as f32, f32::MIN); + assert!(min.is_normal()); + + let min_positive: f64 = f32::MIN_POSITIVE.into(); + assert_eq!(min_positive as f32, f32::MIN_POSITIVE); + assert!(min_positive.is_normal()); + + let epsilon: f64 = f32::EPSILON.into(); + assert_eq!(epsilon as f32, f32::EPSILON); + assert!(epsilon.is_normal()); + + let zero: f64 = (0.0f32).into(); + assert_eq!(zero as f32, 0.0f32); + assert!(zero.is_sign_positive()); + + let neg_zero: f64 = (-0.0f32).into(); + assert_eq!(neg_zero as f32, -0.0f32); + assert!(neg_zero.is_sign_negative()); + + let infinity: f64 = f32::INFINITY.into(); + assert_eq!(infinity as f32, f32::INFINITY); + assert!(infinity.is_infinite()); + assert!(infinity.is_sign_positive()); + + let neg_infinity: f64 = f32::NEG_INFINITY.into(); + assert_eq!(neg_infinity as f32, f32::NEG_INFINITY); + assert!(neg_infinity.is_infinite()); + assert!(neg_infinity.is_sign_negative()); + + let nan: f64 = f32::NAN.into(); + assert!(nan.is_nan());*/ + + /*use std::convert::TryFrom; /*let max = ::MAX; let min = ::MIN;*/ @@ -35,4 +159,5 @@ fn main() { >::try_from(t_min as i128).unwrap(), t_min as u64 );*/ + */ } diff --git a/src/builder.rs b/src/builder.rs index e12184a8931..94ea7a01c9b 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -123,7 +123,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { }; let cond1 = self.context.new_comparison(None, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(None, src, previous_value.get_type())); - let compare_exchange = self.compare_exchange(dst, previous_var.to_rvalue(), src, order, load_ordering, false); + let compare_exchange = self.compare_exchange(dst, previous_var, src, order, load_ordering, false); let cond2 = self.cx.context.new_unary_op(None, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange); let cond = self.cx.context.new_binary_op(None, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2); @@ -137,7 +137,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { return_value.to_rvalue() } - fn compare_exchange(&self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> { + fn compare_exchange(&self, dst: RValue<'gcc>, cmp: LValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> { let size = self.cx.int_width(src.get_type()); let compare_exchange = self.context.get_builtin_function(&format!("__atomic_compare_exchange_{}", size / 8)); let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); @@ -147,9 +147,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let void_ptr_type = self.context.new_type::<*mut ()>(); let volatile_void_ptr_type = void_ptr_type.make_volatile(); let dst = self.context.new_cast(None, dst, volatile_void_ptr_type); - let expected = self.current_func().new_local(None, cmp.get_type(), "expected"); - self.llbb().add_assignment(None, expected, cmp); - let expected = self.context.new_cast(None, expected.get_address(None), void_ptr_type); + let expected = self.context.new_cast(None, cmp.get_address(None), void_ptr_type); // NOTE: not sure why, but we need to cast to the signed type. let new_src_type = @@ -1494,7 +1492,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // Atomic Operations fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> { - let success = self.compare_exchange(dst, cmp, src, order, failure_order, weak); + let expected = self.current_func().new_local(None, cmp.get_type(), "expected"); + self.llbb().add_assignment(None, expected, cmp); + let success = self.compare_exchange(dst, expected, src, order, failure_order, weak); let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false); let result = self.current_func().new_local(None, pair_type, "atomic_cmpxchg_result"); @@ -1502,9 +1502,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let value_type = result.to_rvalue().get_type(); if let Some(struct_type) = value_type.is_struct() { - self.store(cmp, result.access_field(None, struct_type.get_field(0)).get_address(None), align); self.store(success, result.access_field(None, struct_type.get_field(1)).get_address(None), align); + // NOTE: since success contains the call to the intrinsic, it must be stored before + // expected so that we store expected after the call. + self.store(expected.to_rvalue(), result.access_field(None, struct_type.get_field(0)).get_address(None), align); } + // TODO: handle when value is not a struct. result.to_rvalue() }