Skip to content

Commit 48b0ebe

Browse files
committed
add simd_extract_dyn and simd_insert_dyn
1 parent f04bbc6 commit 48b0ebe

File tree

6 files changed

+199
-4
lines changed

6 files changed

+199
-4
lines changed

compiler/rustc_codegen_llvm/src/intrinsic.rs

+24
Original file line numberDiff line numberDiff line change
@@ -1451,6 +1451,23 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
14511451
bx.const_i32(idx as i32),
14521452
));
14531453
}
1454+
if name == sym::simd_insert_dyn {
1455+
require!(
1456+
in_elem == arg_tys[2],
1457+
InvalidMonomorphization::InsertedType {
1458+
span,
1459+
name,
1460+
in_elem,
1461+
in_ty,
1462+
out_ty: arg_tys[2]
1463+
}
1464+
);
1465+
return Ok(bx.insert_element(
1466+
args[0].immediate(),
1467+
args[2].immediate(),
1468+
args[1].immediate(),
1469+
));
1470+
}
14541471
if name == sym::simd_extract {
14551472
require!(
14561473
ret_ty == in_elem,
@@ -1469,6 +1486,13 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
14691486
}
14701487
return Ok(bx.extract_element(args[0].immediate(), bx.const_i32(idx as i32)));
14711488
}
1489+
if name == sym::simd_extract_dyn {
1490+
require!(
1491+
ret_ty == in_elem,
1492+
InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
1493+
);
1494+
return Ok(bx.extract_element(args[0].immediate(), args[1].immediate()));
1495+
}
14721496

14731497
if name == sym::simd_select {
14741498
let m_elem_ty = in_elem;

compiler/rustc_hir_analysis/src/check/intrinsic.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -682,8 +682,12 @@ pub fn check_intrinsic_type(
682682
sym::simd_masked_load => (3, 0, vec![param(0), param(1), param(2)], param(2)),
683683
sym::simd_masked_store => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit),
684684
sym::simd_scatter => (3, 0, vec![param(0), param(1), param(2)], tcx.types.unit),
685-
sym::simd_insert => (2, 0, vec![param(0), tcx.types.u32, param(1)], param(0)),
686-
sym::simd_extract => (2, 0, vec![param(0), tcx.types.u32], param(1)),
685+
sym::simd_insert | sym::simd_insert_dyn => {
686+
(2, 0, vec![param(0), tcx.types.u32, param(1)], param(0))
687+
}
688+
sym::simd_extract | sym::simd_extract_dyn => {
689+
(2, 0, vec![param(0), tcx.types.u32], param(1))
690+
}
687691
sym::simd_cast
688692
| sym::simd_as
689693
| sym::simd_cast_ptr

compiler/rustc_span/src/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1874,6 +1874,7 @@ symbols! {
18741874
simd_eq,
18751875
simd_expose_provenance,
18761876
simd_extract,
1877+
simd_extract_dyn,
18771878
simd_fabs,
18781879
simd_fcos,
18791880
simd_fexp,
@@ -1894,6 +1895,7 @@ symbols! {
18941895
simd_ge,
18951896
simd_gt,
18961897
simd_insert,
1898+
simd_insert_dyn,
18971899
simd_le,
18981900
simd_lt,
18991901
simd_masked_load,

library/core/src/intrinsics/simd.rs

+39-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
/// Inserts an element into a vector, returning the updated vector.
66
///
7-
/// `T` must be a vector with element type `U`.
7+
/// `T` must be a vector with element type `U`, and `idx` must be const.
88
///
99
/// # Safety
1010
///
@@ -16,20 +16,57 @@ pub unsafe fn simd_insert<T, U>(_x: T, _idx: u32, _val: U) -> T {
1616
unreachable!()
1717
}
1818

19-
/// Extracts an element from a vector.
19+
/// Inserts an element into a vector, returning the updated vector.
2020
///
2121
/// `T` must be a vector with element type `U`.
2222
///
23+
/// If the index is `const`, using [`simd_insert`] instead may emit better assembly.
24+
///
2325
/// # Safety
2426
///
2527
/// `idx` must be in-bounds of the vector.
28+
#[rustc_nounwind]
29+
#[inline]
30+
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
31+
pub const unsafe fn simd_insert_dyn<T, U>(mut x: T, idx: u32, val: U) -> T {
32+
// SAFETY: `idx` must be in-bounds
33+
unsafe { (&mut x as *mut T as *mut U).add(idx as usize).write(val) }
34+
x
35+
}
36+
37+
/// Extracts an element from a vector.
38+
///
39+
/// `T` must be a vector with element type `U`, and `idx` must be const.
40+
///
41+
/// # Safety
42+
///
43+
/// `idx` must be const and in-bounds of the vector.
2644
#[rustc_intrinsic]
2745
#[rustc_intrinsic_must_be_overridden]
2846
#[rustc_nounwind]
2947
pub unsafe fn simd_extract<T, U>(_x: T, _idx: u32) -> U {
3048
unreachable!()
3149
}
3250

51+
/// Extracts an element from a vector.
52+
///
53+
/// `T` must be a vector with element type `U`.
54+
///
55+
/// If the index is `const`, using [`simd_extract`] instead may emit better assembly.
56+
///
57+
/// # Safety
58+
///
59+
/// `idx` must be in-bounds of the vector.
60+
#[rustc_nounwind]
61+
#[inline]
62+
#[cfg_attr(not(bootstrap), rustc_intrinsic)]
63+
pub const unsafe fn simd_extract_dyn<T, U>(x: T, idx: u32) -> U {
64+
// SAFETY: `idx` must be in-bounds
65+
let e = unsafe { (&x as *const T as *const U).add(idx as usize).read() };
66+
core::mem::forget(x);
67+
e
68+
}
69+
3370
/// Adds two simd vectors elementwise.
3471
///
3572
/// `T` must be a vector of integer or floating point primitive types.
+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//@compile-flags: -Copt-level=3 -Z merge-functions=disabled
2+
3+
#![feature(core_intrinsics, s390x_target_feature, repr_simd)]
4+
#![no_std]
5+
#![crate_type = "lib"]
6+
#![allow(non_camel_case_types)]
7+
8+
// Test that
9+
//
10+
// - `core::intrinsics::simd::simd_extract_dyn` is lowered to an `extractelement`
11+
// - `core::intrinsics::simd::simd_insert_dyn` is lowered to an `insertelement`
12+
//
13+
// On many platforms (e.g. x86_64) this will ultimately lower to a pointer load, but some platforms
14+
// (e.g. s390x, powerpc) have dedicated instructions for these operations.
15+
16+
use core::intrinsics::simd::{simd_extract, simd_extract_dyn, simd_insert, simd_insert_dyn};
17+
18+
#[repr(simd)]
19+
#[derive(Clone, Copy)]
20+
pub struct u32x16([u32; 16]);
21+
22+
#[repr(simd)]
23+
#[derive(Clone, Copy)]
24+
pub struct i8x16([i8; 16]);
25+
26+
// CHECK-LABEL: dyn_simd_extract
27+
// CHECK: extractelement <16 x i8> %x, i32 %idx
28+
// CHECK-NEXT: ret
29+
#[no_mangle]
30+
unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 {
31+
simd_extract_dyn(x, idx)
32+
}
33+
34+
// CHECK-LABEL: literal_dyn_simd_extract
35+
// CHECK: extractelement <16 x i8> %x, i64 7
36+
// CHECK-NEXT: ret
37+
#[no_mangle]
38+
unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 {
39+
simd_extract_dyn(x, 7)
40+
}
41+
42+
// CHECK-LABEL: const_dyn_simd_extract
43+
// CHECK: extractelement <16 x i8> %x, i64 7
44+
// CHECK-NEXT: ret
45+
#[no_mangle]
46+
unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 {
47+
simd_extract_dyn(x, const { 3 + 4 })
48+
}
49+
50+
// CHECK-LABEL: const_simd_extract
51+
// CHECK: extractelement <16 x i8> %x, i64 7
52+
// CHECK-NEXT: ret
53+
#[no_mangle]
54+
unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 {
55+
simd_extract(x, const { 3 + 4 })
56+
}
57+
58+
// CHECK-LABEL: dyn_simd_insert
59+
// CHECK: insertelement <16 x i8> %x, i8 %e, i32 %idx
60+
// CHECK-NEXT: ret
61+
#[no_mangle]
62+
unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 {
63+
simd_insert_dyn(x, idx, e)
64+
}
65+
66+
// CHECK-LABEL: literal_dyn_simd_insert
67+
// CHECK: insertelement <16 x i8> %x, i8 %e, i64 7
68+
// CHECK-NEXT: ret
69+
#[no_mangle]
70+
unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 {
71+
simd_insert_dyn(x, 7, e)
72+
}
73+
74+
// CHECK-LABEL: const_dyn_simd_insert
75+
// CHECK: insertelement <16 x i8> %x, i8 %e, i64 7
76+
// CHECK-NEXT: ret
77+
#[no_mangle]
78+
unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 {
79+
simd_insert_dyn(x, const { 3 + 4 }, e)
80+
}
81+
82+
// CHECK-LABEL: const_simd_insert
83+
// CHECK: insertelement <16 x i8> %x, i8 %e, i64 7
84+
// CHECK-NEXT: ret
85+
#[no_mangle]
86+
unsafe extern "C" fn const_simd_insert(x: i8x16, e: i8) -> i8x16 {
87+
simd_insert(x, const { 3 + 4 }, e)
88+
}

tests/ui/simd/intrinsic/generic-elements-pass.rs

+40
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,14 @@ struct i32x8([i32; 8]);
1919
#[rustc_intrinsic]
2020
unsafe fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T;
2121

22+
#[rustc_intrinsic]
23+
unsafe fn simd_insert_dyn<T, E>(x: T, idx: u32, y: E) -> T;
24+
2225
#[rustc_intrinsic]
2326
unsafe fn simd_extract<T, E>(x: T, idx: u32) -> E;
2427

28+
#[rustc_intrinsic]
29+
unsafe fn simd_extract_dyn<T, E>(x: T, idx: u32) -> E;
2530

2631
#[rustc_intrinsic]
2732
unsafe fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
@@ -79,6 +84,41 @@ fn main() {
7984
all_eq!(simd_extract(x8, 6), 86);
8085
all_eq!(simd_extract(x8, 7), 87);
8186
}
87+
unsafe {
88+
all_eq!(simd_insert_dyn(x2, 0, 100), i32x2([100, 21]));
89+
all_eq!(simd_insert_dyn(x2, 1, 100), i32x2([20, 100]));
90+
91+
all_eq!(simd_insert_dyn(x4, 0, 100), i32x4([100, 41, 42, 43]));
92+
all_eq!(simd_insert_dyn(x4, 1, 100), i32x4([40, 100, 42, 43]));
93+
all_eq!(simd_insert_dyn(x4, 2, 100), i32x4([40, 41, 100, 43]));
94+
all_eq!(simd_insert_dyn(x4, 3, 100), i32x4([40, 41, 42, 100]));
95+
96+
all_eq!(simd_insert_dyn(x8, 0, 100), i32x8([100, 81, 82, 83, 84, 85, 86, 87]));
97+
all_eq!(simd_insert_dyn(x8, 1, 100), i32x8([80, 100, 82, 83, 84, 85, 86, 87]));
98+
all_eq!(simd_insert_dyn(x8, 2, 100), i32x8([80, 81, 100, 83, 84, 85, 86, 87]));
99+
all_eq!(simd_insert_dyn(x8, 3, 100), i32x8([80, 81, 82, 100, 84, 85, 86, 87]));
100+
all_eq!(simd_insert_dyn(x8, 4, 100), i32x8([80, 81, 82, 83, 100, 85, 86, 87]));
101+
all_eq!(simd_insert_dyn(x8, 5, 100), i32x8([80, 81, 82, 83, 84, 100, 86, 87]));
102+
all_eq!(simd_insert_dyn(x8, 6, 100), i32x8([80, 81, 82, 83, 84, 85, 100, 87]));
103+
all_eq!(simd_insert_dyn(x8, 7, 100), i32x8([80, 81, 82, 83, 84, 85, 86, 100]));
104+
105+
all_eq!(simd_extract_dyn(x2, 0), 20);
106+
all_eq!(simd_extract_dyn(x2, 1), 21);
107+
108+
all_eq!(simd_extract_dyn(x4, 0), 40);
109+
all_eq!(simd_extract_dyn(x4, 1), 41);
110+
all_eq!(simd_extract_dyn(x4, 2), 42);
111+
all_eq!(simd_extract_dyn(x4, 3), 43);
112+
113+
all_eq!(simd_extract_dyn(x8, 0), 80);
114+
all_eq!(simd_extract_dyn(x8, 1), 81);
115+
all_eq!(simd_extract_dyn(x8, 2), 82);
116+
all_eq!(simd_extract_dyn(x8, 3), 83);
117+
all_eq!(simd_extract_dyn(x8, 4), 84);
118+
all_eq!(simd_extract_dyn(x8, 5), 85);
119+
all_eq!(simd_extract_dyn(x8, 6), 86);
120+
all_eq!(simd_extract_dyn(x8, 7), 87);
121+
}
82122

83123
let y2 = i32x2([120, 121]);
84124
let y4 = i32x4([140, 141, 142, 143]);

0 commit comments

Comments
 (0)