Skip to content

Commit 87c0c90

Browse files
authored
Rollup merge of #151346 - folkertdev:simd-splat, r=workingjubilee
add `simd_splat` intrinsic Add `simd_splat` which lowers to the LLVM canonical splat sequence. ```llvm insertelement <N x elem> poison, elem %x, i32 0 shufflevector <N x elem> v0, <N x elem> poison, <N x i32> zeroinitializer ``` Right now we try to fake it using one of ```rust fn splat(x: u32) -> u32x8 { u32x8::from_array([x; 8]) } ``` or (in `stdarch`) ```rust fn splat(value: $elem_type) -> $name { #[derive(Copy, Clone)] #[repr(simd)] struct JustOne([$elem_type; 1]); let one = JustOne([value]); // SAFETY: 0 is always in-bounds because we're shuffling // a simd type with exactly one element. unsafe { simd_shuffle!(one, one, [0; $len]) } } ``` Both of these can confuse the LLVM optimizer, producing sub-par code. Some examples: - rust-lang/rust#60637 - rust-lang/rust#137407 - rust-lang/rust#122623 - rust-lang/rust#97804 --- As far as I can tell there is no way to provide a fallback implementation for this intrinsic, because there is no `const` way of evaluating the number of elements (there might be issues beyond that, too). So, I added implementations for all 4 backends. Both GCC and const-eval appear to have some issues with simd vectors containing pointers. I have a workaround for GCC, but haven't yet been able to make const-eval work. See the comments below. Currently this just adds the intrinsic, it does not actually use it anywhere yet.
2 parents 56d3294 + e0b87e4 commit 87c0c90

1 file changed

Lines changed: 36 additions & 0 deletions

File tree

src/intrinsic/simd.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,42 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
121121
return Ok(bx.vector_select(vector_mask, arg1, args[2].immediate()));
122122
}
123123

124+
#[cfg(feature = "master")]
125+
if name == sym::simd_splat {
126+
let (out_len, out_ty) = require_simd2!(ret_ty, SimdReturn);
127+
128+
require!(
129+
args[0].layout.ty == out_ty,
130+
InvalidMonomorphization::ExpectedVectorElementType {
131+
span,
132+
name,
133+
expected_element: out_ty,
134+
vector_type: ret_ty,
135+
}
136+
);
137+
138+
let vec_ty = llret_ty.unqualified().dyncast_vector().expect("vector return type");
139+
let elem_ty = vec_ty.get_element_type();
140+
141+
// Cast pointer type to usize (GCC does not support pointer SIMD vectors).
142+
let value = args[0];
143+
let scalar = if value.layout.ty.is_numeric() {
144+
value.immediate()
145+
} else if value.layout.ty.is_raw_ptr() {
146+
bx.ptrtoint(value.immediate(), elem_ty)
147+
} else {
148+
return_error!(InvalidMonomorphization::UnsupportedOperation {
149+
span,
150+
name,
151+
in_ty: ret_ty,
152+
in_elem: value.layout.ty
153+
});
154+
};
155+
156+
let elements = vec![scalar; out_len as usize];
157+
return Ok(bx.context.new_rvalue_from_vector(bx.location, llret_ty, &elements));
158+
}
159+
124160
// every intrinsic below takes a SIMD vector as its first argument
125161
require_simd!(
126162
args[0].layout.ty,

0 commit comments

Comments
 (0)