Skip to content

Commit 6eaa453

Browse files
authored
Use CBMC's shuffle_vector expression (#4204)
Ever since CBMC 5.51.0 it is no longer necessary to lower this expression in Kani. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.
1 parent ab7c438 commit 6eaa453

File tree

4 files changed

+44
-17
lines changed

4 files changed

+44
-17
lines changed

cprover_bindings/src/goto_program/expr.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ pub enum ExprValue {
139139
op: SelfOperator,
140140
e: Expr,
141141
},
142+
ShuffleVector {
143+
vector1: Expr,
144+
vector2: Expr,
145+
indexes: Vec<Expr>,
146+
},
142147
/// <https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html>
143148
/// e.g. `({ int y = foo (); int z; if (y > 0) z = y; else z = - y; z; })`
144149
/// `({ op1; op2; ...})`
@@ -371,6 +376,11 @@ impl Expr {
371376
If { c, t, e } => c.is_side_effect() || t.is_side_effect() || e.is_side_effect(),
372377
Index { array, index } => array.is_side_effect() || index.is_side_effect(),
373378
Member { lhs, field: _ } => lhs.is_side_effect(),
379+
ShuffleVector { vector1, vector2, indexes } => {
380+
vector1.is_side_effect()
381+
|| vector2.is_side_effect()
382+
|| indexes.iter().any(|e| e.is_side_effect())
383+
}
374384
Struct { values } => values.iter().any(|e| e.is_side_effect()),
375385
Typecast(e) => e.is_side_effect(),
376386
Union { value, field: _ } => value.is_side_effect(),
@@ -990,6 +1000,18 @@ impl Expr {
9901000
assert!(variable.is_symbol());
9911001
expr!(Exists { variable, domain }, typ)
9921002
}
1003+
1004+
pub fn shuffle_vector(vector1: Expr, vector2: Expr, indexes: Vec<Expr>) -> Expr {
1005+
assert!(vector1.typ.is_array_like());
1006+
assert!(vector2.typ.is_array_like());
1007+
expr!(
1008+
ShuffleVector { vector1, vector2, indexes },
1009+
Type::vector(
1010+
vector1.typ.base_type().unwrap().clone(),
1011+
indexes.len().try_into().unwrap()
1012+
)
1013+
)
1014+
}
9931015
}
9941016

9951017
/// Constructors for Binary Operations

cprover_bindings/src/irep/irep_id.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ pub enum IrepId {
836836
VectorGt,
837837
VectorLt,
838838
FloatbvRoundToIntegral,
839+
ShuffleVector,
839840
}
840841

841842
impl IrepId {
@@ -1731,6 +1732,7 @@ impl IrepId {
17311732
IrepId::VectorGt => "vector->",
17321733
IrepId::VectorLt => "vector-<",
17331734
IrepId::FloatbvRoundToIntegral => "floatbv_round_to_integral",
1735+
IrepId::ShuffleVector => "shuffle_vector",
17341736
}
17351737
}
17361738
}

cprover_bindings/src/irep/to_irep.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,19 @@ impl ToIrep for ExprValue {
408408
],
409409
named_sub: linear_map![],
410410
},
411+
ExprValue::ShuffleVector { vector1, vector2, indexes } => Irep {
412+
id: IrepId::ShuffleVector,
413+
sub: vec![
414+
vector1.to_irep(mm),
415+
vector2.to_irep(mm),
416+
Irep {
417+
id: IrepId::EmptyString,
418+
sub: indexes.iter().map(|x| x.to_irep(mm)).collect(),
419+
named_sub: linear_map![],
420+
},
421+
],
422+
named_sub: linear_map![],
423+
},
411424
}
412425
}
413426
}

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

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,7 +1556,8 @@ impl GotocCtx<'_> {
15561556
}
15571557

15581558
/// `simd_shuffle` constructs a new vector from the elements of two input
1559-
/// vectors, choosing values according to an input array of indexes.
1559+
/// vectors, choosing values according to an input array of indexes. See
1560+
/// https://doc.rust-lang.org/std/intrinsics/simd/fn.simd_shuffle.html
15601561
///
15611562
/// We check that:
15621563
/// 1. The return type length is equal to the expected length (`n`) of the
@@ -1571,13 +1572,6 @@ impl GotocCtx<'_> {
15711572
/// TODO: Check that `indexes` contains constant values which are within the
15721573
/// expected bounds. See
15731574
/// <https://github.com/model-checking/kani/issues/1960> for more details.
1574-
///
1575-
/// This code mimics CBMC's `shuffle_vector_exprt::lower()` here:
1576-
/// <https://github.com/diffblue/cbmc/blob/develop/src/ansi-c/c_expr.cpp>
1577-
///
1578-
/// We can't use shuffle_vector_exprt because it's not understood by the CBMC backend,
1579-
/// it's immediately lowered by the C frontend.
1580-
/// Issue: <https://github.com/diffblue/cbmc/issues/6297>
15811575
fn codegen_intrinsic_simd_shuffle(
15821576
&mut self,
15831577
mut fargs: Vec<Expr>,
@@ -1593,7 +1587,7 @@ impl GotocCtx<'_> {
15931587
// [u32; n]: translated wrapped in a struct
15941588
let indexes = fargs.remove(0);
15951589

1596-
let (in_type_len, vec_subtype) = self.simd_size_and_type(rust_arg_types[0]);
1590+
let (_, vec_subtype) = self.simd_size_and_type(rust_arg_types[0]);
15971591
let (ret_type_len, ret_type_subtype) = self.simd_size_and_type(rust_ret_type);
15981592
if ret_type_len != n {
15991593
let err_msg = format!(
@@ -1617,24 +1611,20 @@ impl GotocCtx<'_> {
16171611
// An unsigned type here causes an invariant violation in CBMC.
16181612
// Issue: https://github.com/diffblue/cbmc/issues/6298
16191613
let st_rep = Type::ssize_t();
1620-
let n_rep = Expr::int_constant(in_type_len, st_rep.clone());
16211614

1622-
// P = indexes.expanded_map(v -> if v < N then vec1[v] else vec2[v-N])
16231615
let elems = (0..n)
16241616
.map(|i| {
16251617
let idx = Expr::int_constant(i, st_rep.clone());
16261618
// Must not use `indexes.index(i)` directly, because codegen wraps arrays in struct
1627-
let v = self.codegen_idx_array(indexes.clone(), idx).cast_to(st_rep.clone());
1628-
let cond = v.clone().lt(n_rep.clone());
1629-
let t = vec1.clone().index(v.clone());
1630-
let e = vec2.clone().index(v.sub(n_rep.clone()));
1631-
cond.ternary(t, e)
1619+
self.codegen_idx_array(indexes.clone(), idx).cast_to(st_rep.clone())
16321620
})
16331621
.collect();
16341622
self.tcx.dcx().abort_if_errors();
16351623
let cbmc_ret_ty = self.codegen_ty_stable(rust_ret_type);
16361624
let loc = self.codegen_span_stable(span);
1637-
self.codegen_expr_to_place_stable(p, Expr::vector_expr(cbmc_ret_ty, elems), loc)
1625+
let shuffle_vector = Expr::shuffle_vector(vec1, vec2, elems);
1626+
assert_eq!(*shuffle_vector.typ(), cbmc_ret_ty);
1627+
self.codegen_expr_to_place_stable(p, shuffle_vector, loc)
16381628
}
16391629

16401630
/// A volatile load of a memory location:

0 commit comments

Comments
 (0)