Skip to content

Commit fb03ccb

Browse files
adpaco-awsdanielsn
andauthored
Add support for atomic_min* and atomic_umin* intrinsics (rust-lang#1212)
* Define `min` expression * Add `atomic_min*` intrinsics * Add test and remove negative ones * Add support for `atomic_umin*` * Add test for `umin` and remove negative ones * Complete `is_side_effect` and use in `min` * Use `any` instead of local function Co-authored-by: Daniel Schwartz-Narbonne <[email protected]>
1 parent ed566c1 commit fb03ccb

File tree

14 files changed

+134
-221
lines changed

14 files changed

+134
-221
lines changed

cprover_bindings/src/goto_program/expr.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,33 @@ impl Expr {
282282
_ => false,
283283
}
284284
}
285+
286+
/// Returns whether an expression causes side effects or not
285287
pub fn is_side_effect(&self) -> bool {
286-
match *self.value {
288+
match &*self.value {
289+
// These expressions always cause side effects
287290
Assign { .. }
288291
| FunctionCall { .. }
289292
| Nondet
290293
| SelfOp { .. }
291294
| StatementExpression { .. } => true,
295+
// These expressions do not cause side effects, but the expressions
296+
// they contain may do. All we need to do are recursive calls.
297+
AddressOf(e) => e.is_side_effect(),
298+
Array { elems } => elems.iter().any(|e| e.is_side_effect()),
299+
ArrayOf { elem } => elem.is_side_effect(),
300+
BinOp { op: _, lhs, rhs } => lhs.is_side_effect() || rhs.is_side_effect(),
301+
ByteExtract { e, offset: _ } => e.is_side_effect(),
302+
Dereference(e) => e.is_side_effect(),
303+
If { c, t, e } => c.is_side_effect() || t.is_side_effect() || e.is_side_effect(),
304+
Index { array, index } => array.is_side_effect() || index.is_side_effect(),
305+
Member { lhs, field: _ } => lhs.is_side_effect(),
306+
Struct { values } => values.iter().any(|e| e.is_side_effect()),
307+
Typecast(e) => e.is_side_effect(),
308+
Union { value, field: _ } => value.is_side_effect(),
309+
UnOp { op: _, e } => e.is_side_effect(),
310+
Vector { elems } => elems.iter().any(|e| e.is_side_effect()),
311+
// The rest of expressions (constants) do not cause side effects
292312
_ => false,
293313
}
294314
}
@@ -1080,6 +1100,15 @@ impl Expr {
10801100
pub fn r_ok(self, e: Expr) -> Expr {
10811101
self.binop(ROk, e)
10821102
}
1103+
1104+
// Expressions defined on top of other expressions
1105+
1106+
/// `min(self, e)`
1107+
pub fn min(self, e: Expr) -> Expr {
1108+
assert!(!self.is_side_effect() && !e.is_side_effect());
1109+
let cmp = self.clone().lt(e.clone());
1110+
cmp.ternary(self, e)
1111+
}
10831112
}
10841113

10851114
/// Constructors for self operations

kani-compiler/src/codegen_cprover_gotoc/codegen/intrinsic.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,11 @@ impl<'tcx> GotocCtx<'tcx> {
412412
"atomic_load_acq" => self.codegen_atomic_load(intrinsic, fargs, p, loc),
413413
"atomic_load_relaxed" => self.codegen_atomic_load(intrinsic, fargs, p, loc),
414414
"atomic_load_unordered" => self.codegen_atomic_load(intrinsic, fargs, p, loc),
415+
"atomic_min" => codegen_atomic_binop!(min),
416+
"atomic_min_acq" => codegen_atomic_binop!(min),
417+
"atomic_min_acqrel" => codegen_atomic_binop!(min),
418+
"atomic_min_rel" => codegen_atomic_binop!(min),
419+
"atomic_min_relaxed" => codegen_atomic_binop!(min),
415420
"atomic_nand" => codegen_atomic_binop!(bitnand),
416421
"atomic_nand_acq" => codegen_atomic_binop!(bitnand),
417422
"atomic_nand_acqrel" => codegen_atomic_binop!(bitnand),
@@ -430,6 +435,11 @@ impl<'tcx> GotocCtx<'tcx> {
430435
"atomic_store_rel" => self.codegen_atomic_store(intrinsic, fargs, p, loc),
431436
"atomic_store_relaxed" => self.codegen_atomic_store(intrinsic, fargs, p, loc),
432437
"atomic_store_unordered" => self.codegen_atomic_store(intrinsic, fargs, p, loc),
438+
"atomic_umin" => codegen_atomic_binop!(min),
439+
"atomic_umin_acq" => codegen_atomic_binop!(min),
440+
"atomic_umin_acqrel" => codegen_atomic_binop!(min),
441+
"atomic_umin_rel" => codegen_atomic_binop!(min),
442+
"atomic_umin_relaxed" => codegen_atomic_binop!(min),
433443
"atomic_xadd" => codegen_atomic_binop!(plus),
434444
"atomic_xadd_acq" => codegen_atomic_binop!(plus),
435445
"atomic_xadd_acqrel" => codegen_atomic_binop!(plus),
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
// Check that `atomic_min` and other variants (unstable version) return the
5+
// expected result.
6+
7+
#![feature(core_intrinsics)]
8+
use std::intrinsics::{
9+
atomic_min, atomic_min_acq, atomic_min_acqrel, atomic_min_rel, atomic_min_relaxed,
10+
};
11+
12+
#[kani::proof]
13+
fn main() {
14+
let mut a1 = 1 as u8;
15+
let mut a2 = 1 as u8;
16+
let mut a3 = 1 as u8;
17+
let mut a4 = 1 as u8;
18+
let mut a5 = 1 as u8;
19+
20+
let ptr_a1: *mut u8 = &mut a1;
21+
let ptr_a2: *mut u8 = &mut a2;
22+
let ptr_a3: *mut u8 = &mut a3;
23+
let ptr_a4: *mut u8 = &mut a4;
24+
let ptr_a5: *mut u8 = &mut a5;
25+
26+
let b = 0 as u8;
27+
28+
unsafe {
29+
let x1 = atomic_min(ptr_a1, b);
30+
let x2 = atomic_min_acq(ptr_a2, b);
31+
let x3 = atomic_min_acqrel(ptr_a3, b);
32+
let x4 = atomic_min_rel(ptr_a4, b);
33+
let x5 = atomic_min_relaxed(ptr_a5, b);
34+
35+
assert!(x1 == 1);
36+
assert!(x2 == 1);
37+
assert!(x3 == 1);
38+
assert!(x4 == 1);
39+
assert!(x5 == 1);
40+
41+
assert!(*ptr_a1 == b);
42+
assert!(*ptr_a2 == b);
43+
assert!(*ptr_a3 == b);
44+
assert!(*ptr_a4 == b);
45+
assert!(*ptr_a5 == b);
46+
}
47+
}

tests/kani/Intrinsics/Atomic/Unstable/AtomicMin/min.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/kani/Intrinsics/Atomic/Unstable/AtomicMin/min_acq.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/kani/Intrinsics/Atomic/Unstable/AtomicMin/min_acqrel.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/kani/Intrinsics/Atomic/Unstable/AtomicMin/min_rel.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/kani/Intrinsics/Atomic/Unstable/AtomicMin/min_relaxed.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright Kani Contributors
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
// Check that `atomic_umin` and other variants (unstable version) return the
5+
// expected result.
6+
7+
#![feature(core_intrinsics)]
8+
use std::intrinsics::{
9+
atomic_umin, atomic_umin_acq, atomic_umin_acqrel, atomic_umin_rel, atomic_umin_relaxed,
10+
};
11+
12+
#[kani::proof]
13+
fn main() {
14+
let mut a1 = 1 as u8;
15+
let mut a2 = 1 as u8;
16+
let mut a3 = 1 as u8;
17+
let mut a4 = 1 as u8;
18+
let mut a5 = 1 as u8;
19+
20+
let ptr_a1: *mut u8 = &mut a1;
21+
let ptr_a2: *mut u8 = &mut a2;
22+
let ptr_a3: *mut u8 = &mut a3;
23+
let ptr_a4: *mut u8 = &mut a4;
24+
let ptr_a5: *mut u8 = &mut a5;
25+
26+
let b = 0 as u8;
27+
28+
unsafe {
29+
let x1 = atomic_umin(ptr_a1, b);
30+
let x2 = atomic_umin_acq(ptr_a2, b);
31+
let x3 = atomic_umin_acqrel(ptr_a3, b);
32+
let x4 = atomic_umin_rel(ptr_a4, b);
33+
let x5 = atomic_umin_relaxed(ptr_a5, b);
34+
35+
assert!(x1 == 1);
36+
assert!(x2 == 1);
37+
assert!(x3 == 1);
38+
assert!(x4 == 1);
39+
assert!(x5 == 1);
40+
41+
assert!(*ptr_a1 == b);
42+
assert!(*ptr_a2 == b);
43+
assert!(*ptr_a3 == b);
44+
assert!(*ptr_a4 == b);
45+
assert!(*ptr_a5 == b);
46+
}
47+
}

tests/kani/Intrinsics/Atomic/Unstable/AtomicUmin/umin.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/kani/Intrinsics/Atomic/Unstable/AtomicUmin/umin_acq.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/kani/Intrinsics/Atomic/Unstable/AtomicUmin/umin_acqrel.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/kani/Intrinsics/Atomic/Unstable/AtomicUmin/umin_rel.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)