Implement simd_gather
This commit is contained in:
parent
8d0ff6bf07
commit
0898eab220
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -41,7 +41,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gccjit"
|
name = "gccjit"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "git+https://github.com/antoyo/gccjit.rs#1e6ecc67fe73ac995e511516eacf4fe3aec8974e"
|
source = "git+https://github.com/antoyo/gccjit.rs#1bd270d0d130fe31807cfbe509ca095c082e5848"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gccjit_sys",
|
"gccjit_sys",
|
||||||
]
|
]
|
||||||
@ -49,7 +49,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gccjit_sys"
|
name = "gccjit_sys"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
source = "git+https://github.com/antoyo/gccjit.rs#1e6ecc67fe73ac995e511516eacf4fe3aec8974e"
|
source = "git+https://github.com/antoyo/gccjit.rs#1bd270d0d130fe31807cfbe509ca095c082e5848"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.1.12",
|
"libc 0.1.12",
|
||||||
]
|
]
|
||||||
|
@ -1419,7 +1419,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||||||
impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
||||||
#[cfg(feature="master")]
|
#[cfg(feature="master")]
|
||||||
pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> {
|
pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> {
|
||||||
let struct_type = mask.get_type().is_struct().expect("mask of struct type");
|
let struct_type = mask.get_type().is_struct().expect("mask should be of struct type");
|
||||||
|
|
||||||
// TODO(antoyo): use a recursive unqualified() here.
|
// TODO(antoyo): use a recursive unqualified() here.
|
||||||
let vector_type = v1.get_type().unqualified().dyncast_vector().expect("vector type");
|
let vector_type = v1.get_type().unqualified().dyncast_vector().expect("vector type");
|
||||||
|
@ -14,6 +14,7 @@ use rustc_span::{Span, Symbol, sym};
|
|||||||
use rustc_target::abi::Align;
|
use rustc_target::abi::Align;
|
||||||
|
|
||||||
use crate::builder::Builder;
|
use crate::builder::Builder;
|
||||||
|
use crate::context::CodegenCx;
|
||||||
|
|
||||||
pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result<RValue<'gcc>, ()> {
|
pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result<RValue<'gcc>, ()> {
|
||||||
// macros for error handling:
|
// macros for error handling:
|
||||||
@ -507,6 +508,156 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
|
|||||||
return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
|
return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn vector_ty<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, elem_ty: Ty<'tcx>, vec_len: u64) -> Type<'gcc> {
|
||||||
|
// FIXME: use cx.layout_of(ty).llvm_type() ?
|
||||||
|
let elem_ty = match *elem_ty.kind() {
|
||||||
|
ty::Int(v) => cx.type_int_from_ty(v),
|
||||||
|
ty::Uint(v) => cx.type_uint_from_ty(v),
|
||||||
|
ty::Float(v) => cx.type_float_from_ty(v),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
cx.type_vector(elem_ty, vec_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == sym::simd_gather {
|
||||||
|
// simd_gather(values: <N x T>, pointers: <N x *_ T>,
|
||||||
|
// mask: <N x i{M}>) -> <N x T>
|
||||||
|
// * N: number of elements in the input vectors
|
||||||
|
// * T: type of the element to load
|
||||||
|
// * M: any integer width is supported, will be truncated to i1
|
||||||
|
|
||||||
|
// All types must be simd vector types
|
||||||
|
require_simd!(in_ty, "first");
|
||||||
|
require_simd!(arg_tys[1], "second");
|
||||||
|
require_simd!(arg_tys[2], "third");
|
||||||
|
require_simd!(ret_ty, "return");
|
||||||
|
|
||||||
|
// Of the same length:
|
||||||
|
let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||||
|
let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
|
||||||
|
require!(
|
||||||
|
in_len == out_len,
|
||||||
|
"expected {} argument with length {} (same as input type `{}`), \
|
||||||
|
found `{}` with length {}",
|
||||||
|
"second",
|
||||||
|
in_len,
|
||||||
|
in_ty,
|
||||||
|
arg_tys[1],
|
||||||
|
out_len
|
||||||
|
);
|
||||||
|
require!(
|
||||||
|
in_len == out_len2,
|
||||||
|
"expected {} argument with length {} (same as input type `{}`), \
|
||||||
|
found `{}` with length {}",
|
||||||
|
"third",
|
||||||
|
in_len,
|
||||||
|
in_ty,
|
||||||
|
arg_tys[2],
|
||||||
|
out_len2
|
||||||
|
);
|
||||||
|
|
||||||
|
// The return type must match the first argument type
|
||||||
|
require!(ret_ty == in_ty, "expected return type `{}`, found `{}`", in_ty, ret_ty);
|
||||||
|
|
||||||
|
// This counts how many pointers
|
||||||
|
fn ptr_count(t: Ty<'_>) -> usize {
|
||||||
|
match t.kind() {
|
||||||
|
ty::RawPtr(p) => 1 + ptr_count(p.ty),
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-ptr type
|
||||||
|
fn non_ptr(t: Ty<'_>) -> Ty<'_> {
|
||||||
|
match t.kind() {
|
||||||
|
ty::RawPtr(p) => non_ptr(p.ty),
|
||||||
|
_ => t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The second argument must be a simd vector with an element type that's a pointer
|
||||||
|
// to the element type of the first argument
|
||||||
|
let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
|
||||||
|
let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
|
||||||
|
let (pointer_count, underlying_ty) = match element_ty1.kind() {
|
||||||
|
ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)),
|
||||||
|
_ => {
|
||||||
|
require!(
|
||||||
|
false,
|
||||||
|
"expected element type `{}` of second argument `{}` \
|
||||||
|
to be a pointer to the element type `{}` of the first \
|
||||||
|
argument `{}`, found `{}` != `*_ {}`",
|
||||||
|
element_ty1,
|
||||||
|
arg_tys[1],
|
||||||
|
in_elem,
|
||||||
|
in_ty,
|
||||||
|
element_ty1,
|
||||||
|
in_elem
|
||||||
|
);
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assert!(pointer_count > 0);
|
||||||
|
assert_eq!(pointer_count - 1, ptr_count(element_ty0));
|
||||||
|
assert_eq!(underlying_ty, non_ptr(element_ty0));
|
||||||
|
|
||||||
|
// The element type of the third argument must be a signed integer type of any width:
|
||||||
|
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
|
||||||
|
match element_ty2.kind() {
|
||||||
|
ty::Int(_) => (),
|
||||||
|
_ => {
|
||||||
|
require!(
|
||||||
|
false,
|
||||||
|
"expected element type `{}` of third argument `{}` \
|
||||||
|
to be a signed integer type",
|
||||||
|
element_ty2,
|
||||||
|
arg_tys[2]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let vector_type =
|
||||||
|
if pointer_count > 1 {
|
||||||
|
bx.context.new_vector_type(bx.usize_type, in_len)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vector_ty(bx, underlying_ty, in_len)
|
||||||
|
};
|
||||||
|
let elem_type = vector_type.dyncast_vector().expect("vector type").get_element_type();
|
||||||
|
|
||||||
|
let mut values = vec![];
|
||||||
|
let pointers = args[1].immediate();
|
||||||
|
for i in 0..in_len {
|
||||||
|
let index = bx.context.new_rvalue_from_long(bx.i32_type, i as i64);
|
||||||
|
let int = bx.context.new_vector_access(None, pointers, index).to_rvalue();
|
||||||
|
|
||||||
|
let ptr_type = elem_type.make_pointer();
|
||||||
|
|
||||||
|
let ptr = bx.context.new_bitcast(None, int, ptr_type);
|
||||||
|
let value = ptr.dereference(None).to_rvalue();
|
||||||
|
values.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let vector = bx.context.new_rvalue_from_vector(None, vector_type, &values);
|
||||||
|
let default = args[0].immediate();
|
||||||
|
let mask = args[2].immediate();
|
||||||
|
|
||||||
|
let mut mask_types = vec![];
|
||||||
|
let mut mask_values = vec![];
|
||||||
|
for i in 0..in_len {
|
||||||
|
let index = bx.context.new_rvalue_from_long(bx.i32_type, i as i64);
|
||||||
|
mask_types.push(bx.context.new_field(None, bx.i32_type, "m")); // TODO: choose an integer based on the size of the vector element type.
|
||||||
|
let mask_value = bx.context.new_vector_access(None, mask, index).to_rvalue();
|
||||||
|
let masked = bx.context.new_rvalue_from_int(bx.i32_type, in_len as i32) & mask_value;
|
||||||
|
let value = index + masked;
|
||||||
|
mask_values.push(value);
|
||||||
|
}
|
||||||
|
let mask_type = bx.context.new_struct_type(None, "mask_type", &mask_types);
|
||||||
|
let mask = bx.context.new_struct_constructor(None, mask_type.as_type(), None, &mask_values);
|
||||||
|
|
||||||
|
return Ok(bx.shuffle_vector(default, vector, mask));
|
||||||
|
}
|
||||||
|
|
||||||
arith_binary! {
|
arith_binary! {
|
||||||
simd_add: Uint, Int => add, Float => fadd;
|
simd_add: Uint, Int => add, Float => fadd;
|
||||||
simd_sub: Uint, Int => sub, Float => fsub;
|
simd_sub: Uint, Int => sub, Float => fsub;
|
||||||
|
@ -55,6 +55,14 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
|
|||||||
Abi::Scalar(_) => bug!("handled elsewhere"),
|
Abi::Scalar(_) => bug!("handled elsewhere"),
|
||||||
Abi::Vector { ref element, count } => {
|
Abi::Vector { ref element, count } => {
|
||||||
let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO);
|
let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO);
|
||||||
|
let element =
|
||||||
|
// NOTE: gcc doesn't allow pointer types in vectors.
|
||||||
|
if element.get_pointee().is_some() {
|
||||||
|
cx.usize_type
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
element
|
||||||
|
};
|
||||||
return cx.context.new_vector_type(element, count);
|
return cx.context.new_vector_type(element, count);
|
||||||
},
|
},
|
||||||
Abi::ScalarPair(..) => {
|
Abi::ScalarPair(..) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user