Skip to content

Commit 7a22c47

Browse files
authored
Merge pull request #254 from rust-lang/feature/simd_scatter_gather
Feature/simd scatter gather
2 parents 8d0ff6b + 16b377e commit 7a22c47

File tree

6 files changed

+295
-6
lines changed

6 files changed

+295
-6
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

failing-ui-tests.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ src/test/ui/sepcomp/sepcomp-fns-backwards.rs
2222
src/test/ui/sepcomp/sepcomp-fns.rs
2323
src/test/ui/sepcomp/sepcomp-statics.rs
2424
src/test/ui/simd/intrinsic/generic-arithmetic-pass.rs
25-
src/test/ui/simd/intrinsic/generic-gather-pass.rs
26-
src/test/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs
2725
src/test/ui/sse2.rs
2826
src/test/ui/target-feature/missing-plusminus.rs
2927
src/test/ui/asm/x86_64/may_unwind.rs
@@ -54,7 +52,6 @@ src/test/ui/issues/issue-43853.rs
5452
src/test/ui/issues/issue-47364.rs
5553
src/test/ui/simd/issue-17170.rs
5654
src/test/ui/simd/issue-39720.rs
57-
src/test/ui/simd/issue-85915-simd-ptrs.rs
5855
src/test/ui/simd/issue-89193.rs
5956
src/test/ui/statics/issue-91050-1.rs
6057
src/test/ui/statics/issue-91050-2.rs

failing-ui-tests12.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,5 @@ src/test/ui/cfg/cfg-panic.rs
3737
src/test/ui/generator/size-moved-locals.rs
3838
src/test/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs
3939
src/test/ui/runtime/rt-explody-panic-payloads.rs
40+
src/test/ui/simd/intrinsic/generic-gather-pass.rs
41+
src/test/ui/simd/issue-85915-simd-ptrs.rs

src/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1419,7 +1419,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
14191419
impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
14201420
#[cfg(feature="master")]
14211421
pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> {
1422-
let struct_type = mask.get_type().is_struct().expect("mask of struct type");
1422+
let struct_type = mask.get_type().is_struct().expect("mask should be of struct type");
14231423

14241424
// TODO(antoyo): use a recursive unqualified() here.
14251425
let vector_type = v1.get_type().unqualified().dyncast_vector().expect("vector type");

src/intrinsic/simd.rs

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use rustc_span::{Span, Symbol, sym};
1414
use rustc_target::abi::Align;
1515

1616
use crate::builder::Builder;
17+
#[cfg(feature="master")]
18+
use crate::context::CodegenCx;
1719

1820
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>, ()> {
1921
// macros for error handling:
@@ -507,6 +509,286 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>,
507509
return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
508510
}
509511

512+
#[cfg(feature="master")]
513+
fn vector_ty<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, elem_ty: Ty<'tcx>, vec_len: u64) -> Type<'gcc> {
514+
// FIXME: use cx.layout_of(ty).llvm_type() ?
515+
let elem_ty = match *elem_ty.kind() {
516+
ty::Int(v) => cx.type_int_from_ty(v),
517+
ty::Uint(v) => cx.type_uint_from_ty(v),
518+
ty::Float(v) => cx.type_float_from_ty(v),
519+
_ => unreachable!(),
520+
};
521+
cx.type_vector(elem_ty, vec_len)
522+
}
523+
524+
#[cfg(feature="master")]
525+
fn gather<'a, 'gcc, 'tcx>(default: RValue<'gcc>, pointers: RValue<'gcc>, mask: RValue<'gcc>, pointer_count: usize, bx: &mut Builder<'a, 'gcc, 'tcx>, in_len: u64, underlying_ty: Ty<'tcx>, invert: bool) -> RValue<'gcc> {
526+
let vector_type =
527+
if pointer_count > 1 {
528+
bx.context.new_vector_type(bx.usize_type, in_len)
529+
}
530+
else {
531+
vector_ty(bx, underlying_ty, in_len)
532+
};
533+
let elem_type = vector_type.dyncast_vector().expect("vector type").get_element_type();
534+
535+
let mut values = vec![];
536+
for i in 0..in_len {
537+
let index = bx.context.new_rvalue_from_long(bx.i32_type, i as i64);
538+
let int = bx.context.new_vector_access(None, pointers, index).to_rvalue();
539+
540+
let ptr_type = elem_type.make_pointer();
541+
let ptr = bx.context.new_bitcast(None, int, ptr_type);
542+
let value = ptr.dereference(None).to_rvalue();
543+
values.push(value);
544+
}
545+
546+
let vector = bx.context.new_rvalue_from_vector(None, vector_type, &values);
547+
548+
let mut mask_types = vec![];
549+
let mut mask_values = vec![];
550+
for i in 0..in_len {
551+
let index = bx.context.new_rvalue_from_long(bx.i32_type, i as i64);
552+
mask_types.push(bx.context.new_field(None, bx.i32_type, "m"));
553+
let mask_value = bx.context.new_vector_access(None, mask, index).to_rvalue();
554+
let masked = bx.context.new_rvalue_from_int(bx.i32_type, in_len as i32) & mask_value;
555+
let value = index + masked;
556+
mask_values.push(value);
557+
}
558+
let mask_type = bx.context.new_struct_type(None, "mask_type", &mask_types);
559+
let mask = bx.context.new_struct_constructor(None, mask_type.as_type(), None, &mask_values);
560+
561+
if invert {
562+
bx.shuffle_vector(vector, default, mask)
563+
}
564+
else {
565+
bx.shuffle_vector(default, vector, mask)
566+
}
567+
}
568+
569+
#[cfg(feature="master")]
570+
if name == sym::simd_gather {
571+
// simd_gather(values: <N x T>, pointers: <N x *_ T>,
572+
// mask: <N x i{M}>) -> <N x T>
573+
// * N: number of elements in the input vectors
574+
// * T: type of the element to load
575+
// * M: any integer width is supported, will be truncated to i1
576+
577+
// All types must be simd vector types
578+
require_simd!(in_ty, "first");
579+
require_simd!(arg_tys[1], "second");
580+
require_simd!(arg_tys[2], "third");
581+
require_simd!(ret_ty, "return");
582+
583+
// Of the same length:
584+
let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
585+
let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
586+
require!(
587+
in_len == out_len,
588+
"expected {} argument with length {} (same as input type `{}`), \
589+
found `{}` with length {}",
590+
"second",
591+
in_len,
592+
in_ty,
593+
arg_tys[1],
594+
out_len
595+
);
596+
require!(
597+
in_len == out_len2,
598+
"expected {} argument with length {} (same as input type `{}`), \
599+
found `{}` with length {}",
600+
"third",
601+
in_len,
602+
in_ty,
603+
arg_tys[2],
604+
out_len2
605+
);
606+
607+
// The return type must match the first argument type
608+
require!(ret_ty == in_ty, "expected return type `{}`, found `{}`", in_ty, ret_ty);
609+
610+
// This counts how many pointers
611+
fn ptr_count(t: Ty<'_>) -> usize {
612+
match t.kind() {
613+
ty::RawPtr(p) => 1 + ptr_count(p.ty),
614+
_ => 0,
615+
}
616+
}
617+
618+
// Non-ptr type
619+
fn non_ptr(t: Ty<'_>) -> Ty<'_> {
620+
match t.kind() {
621+
ty::RawPtr(p) => non_ptr(p.ty),
622+
_ => t,
623+
}
624+
}
625+
626+
// The second argument must be a simd vector with an element type that's a pointer
627+
// to the element type of the first argument
628+
let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
629+
let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
630+
let (pointer_count, underlying_ty) = match element_ty1.kind() {
631+
ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)),
632+
_ => {
633+
require!(
634+
false,
635+
"expected element type `{}` of second argument `{}` \
636+
to be a pointer to the element type `{}` of the first \
637+
argument `{}`, found `{}` != `*_ {}`",
638+
element_ty1,
639+
arg_tys[1],
640+
in_elem,
641+
in_ty,
642+
element_ty1,
643+
in_elem
644+
);
645+
unreachable!();
646+
}
647+
};
648+
assert!(pointer_count > 0);
649+
assert_eq!(pointer_count - 1, ptr_count(element_ty0));
650+
assert_eq!(underlying_ty, non_ptr(element_ty0));
651+
652+
// The element type of the third argument must be a signed integer type of any width:
653+
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
654+
match element_ty2.kind() {
655+
ty::Int(_) => (),
656+
_ => {
657+
require!(
658+
false,
659+
"expected element type `{}` of third argument `{}` \
660+
to be a signed integer type",
661+
element_ty2,
662+
arg_tys[2]
663+
);
664+
}
665+
}
666+
667+
return Ok(gather(args[0].immediate(), args[1].immediate(), args[2].immediate(), pointer_count, bx, in_len, underlying_ty, false));
668+
}
669+
670+
#[cfg(feature="master")]
671+
if name == sym::simd_scatter {
672+
// simd_scatter(values: <N x T>, pointers: <N x *mut T>,
673+
// mask: <N x i{M}>) -> ()
674+
// * N: number of elements in the input vectors
675+
// * T: type of the element to load
676+
// * M: any integer width is supported, will be truncated to i1
677+
678+
// All types must be simd vector types
679+
require_simd!(in_ty, "first");
680+
require_simd!(arg_tys[1], "second");
681+
require_simd!(arg_tys[2], "third");
682+
683+
// Of the same length:
684+
let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
685+
let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
686+
require!(
687+
in_len == element_len1,
688+
"expected {} argument with length {} (same as input type `{}`), \
689+
found `{}` with length {}",
690+
"second",
691+
in_len,
692+
in_ty,
693+
arg_tys[1],
694+
element_len1
695+
);
696+
require!(
697+
in_len == element_len2,
698+
"expected {} argument with length {} (same as input type `{}`), \
699+
found `{}` with length {}",
700+
"third",
701+
in_len,
702+
in_ty,
703+
arg_tys[2],
704+
element_len2
705+
);
706+
707+
// This counts how many pointers
708+
fn ptr_count(t: Ty<'_>) -> usize {
709+
match t.kind() {
710+
ty::RawPtr(p) => 1 + ptr_count(p.ty),
711+
_ => 0,
712+
}
713+
}
714+
715+
// Non-ptr type
716+
fn non_ptr(t: Ty<'_>) -> Ty<'_> {
717+
match t.kind() {
718+
ty::RawPtr(p) => non_ptr(p.ty),
719+
_ => t,
720+
}
721+
}
722+
723+
// The second argument must be a simd vector with an element type that's a pointer
724+
// to the element type of the first argument
725+
let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
726+
let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
727+
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
728+
let (pointer_count, underlying_ty) = match element_ty1.kind() {
729+
ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => {
730+
(ptr_count(element_ty1), non_ptr(element_ty1))
731+
}
732+
_ => {
733+
require!(
734+
false,
735+
"expected element type `{}` of second argument `{}` \
736+
to be a pointer to the element type `{}` of the first \
737+
argument `{}`, found `{}` != `*mut {}`",
738+
element_ty1,
739+
arg_tys[1],
740+
in_elem,
741+
in_ty,
742+
element_ty1,
743+
in_elem
744+
);
745+
unreachable!();
746+
}
747+
};
748+
assert!(pointer_count > 0);
749+
assert_eq!(pointer_count - 1, ptr_count(element_ty0));
750+
assert_eq!(underlying_ty, non_ptr(element_ty0));
751+
752+
// The element type of the third argument must be a signed integer type of any width:
753+
match element_ty2.kind() {
754+
ty::Int(_) => (),
755+
_ => {
756+
require!(
757+
false,
758+
"expected element type `{}` of third argument `{}` \
759+
be a signed integer type",
760+
element_ty2,
761+
arg_tys[2]
762+
);
763+
}
764+
}
765+
766+
let result = gather(args[0].immediate(), args[1].immediate(), args[2].immediate(), pointer_count, bx, in_len, underlying_ty, true);
767+
768+
let pointers = args[1].immediate();
769+
770+
let vector_type =
771+
if pointer_count > 1 {
772+
bx.context.new_vector_type(bx.usize_type, in_len)
773+
}
774+
else {
775+
vector_ty(bx, underlying_ty, in_len)
776+
};
777+
let elem_type = vector_type.dyncast_vector().expect("vector type").get_element_type();
778+
779+
for i in 0..in_len {
780+
let index = bx.context.new_rvalue_from_int(bx.int_type, i as i32);
781+
let value = bx.context.new_vector_access(None, result, index);
782+
783+
let int = bx.context.new_vector_access(None, pointers, index).to_rvalue();
784+
let ptr_type = elem_type.make_pointer();
785+
let ptr = bx.context.new_bitcast(None, int, ptr_type);
786+
bx.llbb().add_assignment(None, ptr.dereference(None), value);
787+
}
788+
789+
return Ok(bx.context.new_rvalue_zero(bx.i32_type));
790+
}
791+
510792
arith_binary! {
511793
simd_add: Uint, Int => add, Float => fadd;
512794
simd_sub: Uint, Int => sub, Float => fsub;

src/type_of.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
5555
Abi::Scalar(_) => bug!("handled elsewhere"),
5656
Abi::Vector { ref element, count } => {
5757
let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO);
58+
let element =
59+
// NOTE: gcc doesn't allow pointer types in vectors.
60+
if element.get_pointee().is_some() {
61+
cx.usize_type
62+
}
63+
else {
64+
element
65+
};
5866
return cx.context.new_vector_type(element, count);
5967
},
6068
Abi::ScalarPair(..) => {

0 commit comments

Comments
 (0)