Skip to content

Commit 17102dc

Browse files
authored
Merge pull request #17 from antoyo/fix-atomic-cmpxchg
Fix atomic_cmpxchg
2 parents 00ea324 + d525086 commit 17102dc

File tree

2 files changed

+136
-8
lines changed

2 files changed

+136
-8
lines changed

Diff for: gcc-test-backend/src/main.rs

+126-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![feature(core_intrinsics)]
2+
13
fn i128_to_u64(u: i128) -> Option<u64> {
24
let min = u64::MIN as i128;
35
//let max = u64::MAX as i128;
@@ -16,7 +18,129 @@ fn i128_to_u64(u: i128) -> Option<u64> {
1618
}
1719

1820
fn main() {
19-
use std::convert::TryFrom;
21+
/*test_float!(f64, f64, f64::INFINITY, f64::NEG_INFINITY, f64::NAN);
22+
($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => {*/
23+
24+
/*assert_eq!((0.0 as f64).min(0.0), 0.0);
25+
assert!((0.0 as f64).min(0.0).is_sign_positive());
26+
assert_eq!((-0.0 as f64).min(-0.0), -0.0);
27+
assert!((-0.0 as f64).min(-0.0).is_sign_negative());
28+
assert_eq!((9.0 as f64).min(9.0), 9.0);
29+
assert_eq!((-9.0 as f64).min(0.0), -9.0);
30+
assert_eq!((0.0 as f64).min(9.0), 0.0);
31+
assert!((0.0 as f64).min(9.0).is_sign_positive());
32+
assert_eq!((-0.0 as f64).min(9.0), -0.0);
33+
assert!((-0.0 as f64).min(9.0).is_sign_negative());*/
34+
35+
//println!("{}", 9);
36+
//println!("{}", 9.0_f32);
37+
//assert_eq!(-9.0_f32, -9 as f32);
38+
39+
//assert_eq!("1", format!("{:.0}", 1.0f64));
40+
//assert_eq!("9", format!("{:.0}", 9.4f64));
41+
//assert_eq!("10", format!("{:.0}", 9.9f64));
42+
//assert_eq!("9.8", format!("{:.1}", 9.849f64));
43+
//assert_eq!("9.9", format!("{:.1}", 9.851f64));
44+
//assert_eq!("1", format!("{:.0}", 0.5f64));
45+
46+
//assert_eq!(2.3f32.copysign(-1.0), -2.3f32);
47+
/*let f = 9.4f32;
48+
println!("{}", f);*/
49+
//println!("{}", 9.4f32); // FIXME: this is using bytes_in_context(), but gives a wrong value.
50+
51+
/*extern {
52+
//pub fn printf(format: *const i8, ...) -> i32;
53+
pub fn printf(format: *const i8, arg: f64) -> i32;
54+
}
55+
56+
unsafe {
57+
printf(b"Num: %f\n\0" as *const _ as *const _, 9.4f64);
58+
}
59+
println!("{}", 9.4f64);*/
60+
61+
let mut value = 0;
62+
let res = unsafe { std::intrinsics::atomic_cxchg(&mut value, 0, 1) };
63+
println!("{:?}", res);
64+
let res = unsafe { std::intrinsics::atomic_cxchg(&mut value, 0, 1) };
65+
println!("{:?}", res);
66+
67+
use std::sync::atomic::{AtomicBool, Ordering};
68+
69+
let a = AtomicBool::new(false);
70+
assert_eq!(a.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst), Ok(false));
71+
assert_eq!(a.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst), Err(true));
72+
73+
a.store(false, Ordering::SeqCst);
74+
assert_eq!(a.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst), Ok(false));
75+
76+
// FIXME: the code seems to be the same when using an integer, but somehow, it doesn't work for
77+
// a float. Could it be related to the fact that floating-points use different registers?
78+
79+
/*let f = 1234567.89f64;
80+
assert_eq!("1.23456789e6", format!("{:e}", f));
81+
println!("{:e}", f);
82+
println!("{:e}", 1234567.89f64);*/
83+
//assert_eq!("1.23456789e6", format!("{:e}", 1234567.89f64));
84+
/*assert_eq!("1.23456789e3", format!("{:e}", 1234.56789f64));
85+
assert_eq!("1.23456789E6", format!("{:E}", 1234567.89f64));
86+
assert_eq!("1.23456789E3", format!("{:E}", 1234.56789f64));
87+
assert_eq!("0.0", format!("{:?}", 0.0f64));
88+
assert_eq!("1.01", format!("{:?}", 1.01f64));*/
89+
90+
/*assert_eq!((-0.0 as f64).min(-9.0), -9.0);
91+
assert_eq!((f64::INFINITY as f64).min(9.0), 9.0);
92+
assert_eq!((9.0 as f64).min(f64::INFINITY), 9.0);
93+
assert_eq!((f64::INFINITY as f64).min(-9.0), -9.0);
94+
assert_eq!((-9.0 as f64).min(f64::INFINITY), -9.0);
95+
assert_eq!((f64::NEG_INFINITY as f64).min(9.0), f64::NEG_INFINITY);
96+
assert_eq!((9.0 as f64).min(f64::NEG_INFINITY), f64::NEG_INFINITY);
97+
assert_eq!((f64::NEG_INFINITY as f64).min(-9.0), f64::NEG_INFINITY);
98+
assert_eq!((-9.0 as f64).min(f64::NEG_INFINITY), f64::NEG_INFINITY);*/
99+
// Cranelift fmin has NaN propagation
100+
//assert_eq!((f64::NAN as f64).min(9.0), 9.0);
101+
//assert_eq!((f64::NAN as f64).min(-9.0), -9.0);
102+
//assert_eq!((9.0 as f64).min(f64::NAN), 9.0);
103+
//assert_eq!((-9.0 as f64).min(f64::NAN), -9.0);
104+
//assert!((f64::NAN as f64).min(f64::NAN).is_nan());
105+
106+
/*let max: f64 = f32::MAX.into();
107+
assert_eq!(max as f32, f32::MAX);
108+
assert!(max.is_normal());
109+
110+
let min: f64 = f32::MIN.into();
111+
assert_eq!(min as f32, f32::MIN);
112+
assert!(min.is_normal());
113+
114+
let min_positive: f64 = f32::MIN_POSITIVE.into();
115+
assert_eq!(min_positive as f32, f32::MIN_POSITIVE);
116+
assert!(min_positive.is_normal());
117+
118+
let epsilon: f64 = f32::EPSILON.into();
119+
assert_eq!(epsilon as f32, f32::EPSILON);
120+
assert!(epsilon.is_normal());
121+
122+
let zero: f64 = (0.0f32).into();
123+
assert_eq!(zero as f32, 0.0f32);
124+
assert!(zero.is_sign_positive());
125+
126+
let neg_zero: f64 = (-0.0f32).into();
127+
assert_eq!(neg_zero as f32, -0.0f32);
128+
assert!(neg_zero.is_sign_negative());
129+
130+
let infinity: f64 = f32::INFINITY.into();
131+
assert_eq!(infinity as f32, f32::INFINITY);
132+
assert!(infinity.is_infinite());
133+
assert!(infinity.is_sign_positive());
134+
135+
let neg_infinity: f64 = f32::NEG_INFINITY.into();
136+
assert_eq!(neg_infinity as f32, f32::NEG_INFINITY);
137+
assert!(neg_infinity.is_infinite());
138+
assert!(neg_infinity.is_sign_negative());
139+
140+
let nan: f64 = f32::NAN.into();
141+
assert!(nan.is_nan());*/
142+
143+
/*use std::convert::TryFrom;
20144
21145
/*let max = <i128>::MAX;
22146
let min = <i128>::MIN;*/
@@ -35,4 +159,5 @@ fn main() {
35159
<u64 as TryFrom<i128>>::try_from(t_min as i128).unwrap(),
36160
t_min as u64
37161
);*/
162+
*/
38163
}

Diff for: src/builder.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
123123
};
124124

125125
let cond1 = self.context.new_comparison(None, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(None, src, previous_value.get_type()));
126-
let compare_exchange = self.compare_exchange(dst, previous_var.to_rvalue(), src, order, load_ordering, false);
126+
let compare_exchange = self.compare_exchange(dst, previous_var, src, order, load_ordering, false);
127127
let cond2 = self.cx.context.new_unary_op(None, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange);
128128
let cond = self.cx.context.new_binary_op(None, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2);
129129

@@ -137,7 +137,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
137137
return_value.to_rvalue()
138138
}
139139

140-
fn compare_exchange(&self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
140+
fn compare_exchange(&self, dst: RValue<'gcc>, cmp: LValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
141141
let size = self.cx.int_width(src.get_type());
142142
let compare_exchange = self.context.get_builtin_function(&format!("__atomic_compare_exchange_{}", size / 8));
143143
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> {
147147
let void_ptr_type = self.context.new_type::<*mut ()>();
148148
let volatile_void_ptr_type = void_ptr_type.make_volatile();
149149
let dst = self.context.new_cast(None, dst, volatile_void_ptr_type);
150-
let expected = self.current_func().new_local(None, cmp.get_type(), "expected");
151-
self.llbb().add_assignment(None, expected, cmp);
152-
let expected = self.context.new_cast(None, expected.get_address(None), void_ptr_type);
150+
let expected = self.context.new_cast(None, cmp.get_address(None), void_ptr_type);
153151

154152
// NOTE: not sure why, but we need to cast to the signed type.
155153
let new_src_type =
@@ -1494,17 +1492,22 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
14941492

14951493
// Atomic Operations
14961494
fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
1497-
let success = self.compare_exchange(dst, cmp, src, order, failure_order, weak);
1495+
let expected = self.current_func().new_local(None, cmp.get_type(), "expected");
1496+
self.llbb().add_assignment(None, expected, cmp);
1497+
let success = self.compare_exchange(dst, expected, src, order, failure_order, weak);
14981498

14991499
let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false);
15001500
let result = self.current_func().new_local(None, pair_type, "atomic_cmpxchg_result");
15011501
let align = Align::from_bits(64).expect("align"); // TODO: use good align.
15021502

15031503
let value_type = result.to_rvalue().get_type();
15041504
if let Some(struct_type) = value_type.is_struct() {
1505-
self.store(cmp, result.access_field(None, struct_type.get_field(0)).get_address(None), align);
15061505
self.store(success, result.access_field(None, struct_type.get_field(1)).get_address(None), align);
1506+
// NOTE: since success contains the call to the intrinsic, it must be stored before
1507+
// expected so that we store expected after the call.
1508+
self.store(expected.to_rvalue(), result.access_field(None, struct_type.get_field(0)).get_address(None), align);
15071509
}
1510+
// TODO: handle when value is not a struct.
15081511

15091512
result.to_rvalue()
15101513
}

0 commit comments

Comments
 (0)