implement simd_bswap intrinsic

Implements lane-local byte swapping through vector shuffles.  While this
is more setup than non-vector shuffles, this implementation can shuffle
multiple integers concurrently.

Signed-off-by: Andy Sadler <andrewsadler122@gmail.com>
This commit is contained in:
Andy Sadler 2023-10-07 23:59:58 -05:00
parent c6bc7ecd65
commit cc7c9bea15
No known key found for this signature in database
GPG Key ID: 7A53357CD58173DD

View File

@ -1,3 +1,5 @@
use std::iter::FromIterator;
use gccjit::ToRValue;
use gccjit::{BinaryOp, RValue, Type};
#[cfg(feature = "master")]
@ -156,6 +158,58 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
return Ok(compare_simd_types(bx, arg1, arg2, in_elem, llret_ty, cmp_op));
}
if name == sym::simd_bswap {
let vector = args[0].immediate();
let ret = match in_elem.kind() {
ty::Int(i) if i.bit_width() == Some(8) => vector,
ty::Uint(i) if i.bit_width() == Some(8) => vector,
ty::Int(_) | ty::Uint(_) => {
let v_type = vector.get_type();
let vector_type = v_type.unqualified().dyncast_vector().expect("vector type");
let elem_type = vector_type.get_element_type();
let elem_size_bytes = elem_type.get_size();
let type_size_bytes = elem_size_bytes as u64 * in_len;
let shuffle_indices = Vec::from_iter(0..type_size_bytes);
let byte_vector_type = bx.context.new_vector_type(bx.type_u8(), type_size_bytes);
let byte_vector = bx.context.new_bitcast(None, args[0].immediate(), byte_vector_type);
#[cfg(not(feature = "master"))]
let shuffled = {
let new_elements: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _)
.flat_map(|x| x.iter().rev())
.map(|&i| {
let index = bx.context.new_rvalue_from_long(bx.u64_type, i as _);
bx.extract_element(byte_vector, index)
})
.collect();
bx.context.new_rvalue_from_vector(None, byte_vector_type, &new_elements)
};
#[cfg(feature = "master")]
let shuffled = {
let indices: Vec<_> = shuffle_indices.chunks_exact(elem_size_bytes as _)
.flat_map(|x| x.iter().rev())
.map(|&i| bx.context.new_rvalue_from_int(bx.u8_type, i as _))
.collect();
let mask = bx.context.new_rvalue_from_vector(None, byte_vector_type, &indices);
bx.context.new_rvalue_vector_perm(None, byte_vector, byte_vector, mask)
};
bx.context.new_bitcast(None, shuffled, v_type)
}
_ => {
return_error!(InvalidMonomorphization::UnsupportedOperation {
span,
name,
in_ty,
in_elem,
});
}
};
return Ok(ret);
}
if name == sym::simd_shuffle {
// Make sure this is actually an array, since typeck only checks the length-suffixed
// version of this intrinsic.