-
Notifications
You must be signed in to change notification settings - Fork 116
Introduce simd_shuffle intrinsic #417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9ad3225
7ab47de
67c4c7b
d6c24b3
d15569a
9f6c6fb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -217,6 +217,11 @@ impl<'tcx> GotocCtx<'tcx> { | |
}}; | ||
} | ||
|
||
if let Some(stripped) = intrinsic.strip_prefix("simd_shuffle") { | ||
let n: u64 = stripped.parse().unwrap(); | ||
return self.codegen_intrinsic_simd_shuffle(fargs, p, cbmc_ret_ty, n); | ||
} | ||
|
||
match intrinsic { | ||
"abort" => Stmt::assert_false("abort intrinsic", loc), | ||
"add_with_overflow" => codegen_op_with_overflow!(add_overflow), | ||
|
@@ -401,6 +406,7 @@ impl<'tcx> GotocCtx<'tcx> { | |
codegen_intrinsic_binop!(lshr) | ||
} | ||
} | ||
// "simd_shuffle#" => handled in an `if` preceding this match | ||
"simd_sub" => codegen_intrinsic_binop!(sub), | ||
"simd_xor" => codegen_intrinsic_binop!(bitxor), | ||
"size_of" => codegen_intrinsic_const!(), | ||
|
@@ -814,6 +820,7 @@ impl<'tcx> GotocCtx<'tcx> { | |
cbmc_ret_ty: Type, | ||
loc: Location, | ||
) -> Stmt { | ||
assert!(fargs.len() == 3, "simd_insert had unexpected arguments {:?}", fargs); | ||
let vec = fargs.remove(0); | ||
let index = fargs.remove(0); | ||
let newval = fargs.remove(0); | ||
|
@@ -829,4 +836,47 @@ impl<'tcx> GotocCtx<'tcx> { | |
loc, | ||
) | ||
} | ||
|
||
/// simd_shuffle constructs a new vector from the elements of two input vectors, | ||
/// choosing values according to an input array of indexes. | ||
/// | ||
/// This code mimics CBMC's `shuffle_vector_exprt::lower()` here: | ||
/// https://github.com/diffblue/cbmc/blob/develop/src/ansi-c/c_expr.cpp | ||
/// | ||
/// We can't use shuffle_vector_exprt because it's not understood by the CBMC backend, | ||
/// it's immediately lowered by the C frontend. | ||
/// Issue: https://github.com/diffblue/cbmc/issues/6297 | ||
pub fn codegen_intrinsic_simd_shuffle( | ||
&mut self, | ||
mut fargs: Vec<Expr>, | ||
p: &Place<'tcx>, | ||
cbmc_ret_ty: Type, | ||
n: u64, | ||
) -> Stmt { | ||
assert!(fargs.len() == 3, "simd_shuffle had unexpected arguments {:?}", fargs); | ||
// vector, size n: translated as vector types which cbmc treats as arrays | ||
let vec1 = fargs.remove(0); | ||
let vec2 = fargs.remove(0); | ||
// [u32; n]: translated wrapped in a struct | ||
let indexes = fargs.remove(0); | ||
|
||
// An unsigned type here causes an invariant violation in CBMC. | ||
// Issue: https://github.com/diffblue/cbmc/issues/6298 | ||
let st_rep = Type::ssize_t(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be clearer to just use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had that thought too, but I felt like keeping it since it created a place for the comment about the CBMC issue. |
||
let n_rep = Expr::int_constant(n, st_rep.clone()); | ||
|
||
// P = indexes.expanded_map(v -> if v < N then vec1[v] else vec2[v-N]) | ||
let elems = (0..n) | ||
.map(|i| { | ||
let i = Expr::int_constant(i, st_rep.clone()); | ||
// Must not use `indexes.index(i)` directly, because codegen wraps arrays in struct | ||
let v = self.codegen_idx_array(indexes.clone(), i).cast_to(st_rep.clone()); | ||
let cond = v.clone().lt(n_rep.clone()); | ||
let t = vec1.clone().index(v.clone()); | ||
let e = vec2.clone().index(v.sub(n_rep.clone())); | ||
cond.ternary(t, e) | ||
}) | ||
.collect(); | ||
self.codegen_expr_to_place(p, Expr::vector_expr(cbmc_ret_ty, elems)) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
#![feature(repr_simd, platform_intrinsics)] | ||
|
||
#[repr(simd)] | ||
#[allow(non_camel_case_types)] | ||
#[derive(Clone, Copy, PartialEq, Eq)] | ||
pub struct i64x2(i64, i64); | ||
|
||
#[repr(simd)] | ||
#[allow(non_camel_case_types)] | ||
#[derive(Clone, Copy, PartialEq, Eq)] | ||
pub struct i64x4(i64, i64, i64, i64); | ||
|
||
extern "platform-intrinsic" { | ||
fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U; | ||
fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U; | ||
} | ||
|
||
fn main() { | ||
{ | ||
let y = i64x2(0, 1); | ||
let z = i64x2(1, 2); | ||
const I: [u32; 2] = [1, 2]; | ||
let x: i64x2 = unsafe { simd_shuffle2(y, z, I) }; | ||
assert!(x.0 == 1); | ||
assert!(x.1 == 1); | ||
} | ||
{ | ||
let a = i64x4(1, 2, 3, 4); | ||
let b = i64x4(5, 6, 7, 8); | ||
const I: [u32; 4] = [1, 3, 5, 7]; | ||
let c: i64x4 = unsafe { simd_shuffle4(a, b, I) }; | ||
assert!(c == i64x4(2, 4, 6, 8)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the
clone
needed hereThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of
value_typ
later is a partial move out of the value.