Skip to content

Commit 3e9d189

Browse files
authored
Rollup merge of rust-lang#64738 - gnzlbg:miri_norm_abi, r=oli-obk
Add const-eval support for SIMD types, insert, and extract This adds initial support for constant-evaluation of Abi::Vector types. r? @oli-obk
2 parents da78127 + 5ecb7eb commit 3e9d189

File tree

5 files changed

+111
-3
lines changed

5 files changed

+111
-3
lines changed

src/librustc_mir/interpret/intrinsics.rs

+45
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,52 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
239239
"transmute" => {
240240
self.copy_op_transmute(args[0], dest)?;
241241
}
242+
"simd_insert" => {
243+
let index = self.read_scalar(args[1])?.to_u32()? as u64;
244+
let scalar = args[2];
245+
let input = args[0];
246+
let (len, e_ty) = self.read_vector_ty(input);
247+
assert!(
248+
index < len,
249+
"Index `{}` must be in bounds of vector type `{}`: `[0, {})`",
250+
index, e_ty, len
251+
);
252+
assert_eq!(
253+
input.layout, dest.layout,
254+
"Return type `{}` must match vector type `{}`",
255+
dest.layout.ty, input.layout.ty
256+
);
257+
assert_eq!(
258+
scalar.layout.ty, e_ty,
259+
"Scalar type `{}` must match vector element type `{}`",
260+
scalar.layout.ty, e_ty
261+
);
242262

263+
for i in 0..len {
264+
let place = self.place_field(dest, i)?;
265+
let value = if i == index {
266+
scalar
267+
} else {
268+
self.operand_field(input, i)?
269+
};
270+
self.copy_op(value, place)?;
271+
}
272+
}
273+
"simd_extract" => {
274+
let index = self.read_scalar(args[1])?.to_u32()? as _;
275+
let (len, e_ty) = self.read_vector_ty(args[0]);
276+
assert!(
277+
index < len,
278+
"index `{}` is out-of-bounds of vector type `{}` with length `{}`",
279+
index, e_ty, len
280+
);
281+
assert_eq!(
282+
e_ty, dest.layout.ty,
283+
"Return type `{}` must match vector element type `{}`",
284+
dest.layout.ty, e_ty
285+
);
286+
self.copy_op(self.operand_field(args[0], index)?, dest)?;
287+
}
243288
_ => return Ok(false),
244289
}
245290

src/librustc_mir/interpret/operand.rs

+11
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
335335
}
336336
}
337337

338+
/// Read vector length and element type
339+
pub fn read_vector_ty(
340+
&self, op: OpTy<'tcx, M::PointerTag>
341+
) -> (u64, &rustc::ty::TyS<'tcx>) {
342+
if let layout::Abi::Vector { .. } = op.layout.abi {
343+
(op.layout.ty.simd_size(*self.tcx) as _, op.layout.ty.simd_type(*self.tcx))
344+
} else {
345+
bug!("Type `{}` is not a SIMD vector type", op.layout.ty)
346+
}
347+
}
348+
338349
/// Read a scalar from a place
339350
pub fn read_scalar(
340351
&self,

src/librustc_mir/interpret/terminator.rs

-3
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
249249

250250
match instance.def {
251251
ty::InstanceDef::Intrinsic(..) => {
252-
if caller_abi != Abi::RustIntrinsic {
253-
throw_unsup!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic))
254-
}
255252
// The intrinsic itself cannot diverge, so if we got here without a return
256253
// place... (can happen e.g., for transmute returning `!`)
257254
let dest = match dest {

src/librustc_mir/transform/qualify_consts.rs

+2
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,8 @@ impl Qualif for IsNotPromotable {
557557
| "saturating_add"
558558
| "saturating_sub"
559559
| "transmute"
560+
| "simd_insert"
561+
| "simd_extract"
560562
=> return true,
561563

562564
_ => {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// run-pass
2+
#![feature(const_fn)]
3+
#![feature(repr_simd)]
4+
#![feature(platform_intrinsics)]
5+
#![allow(non_camel_case_types)]
6+
7+
#[repr(simd)] struct i8x1(i8);
8+
#[repr(simd)] struct u16x2(u16, u16);
9+
#[repr(simd)] struct f32x3(f32, f32, f32);
10+
11+
extern "platform-intrinsic" {
12+
fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
13+
fn simd_extract<T, U>(x: T, idx: u32) -> U;
14+
}
15+
16+
fn main() {
17+
{
18+
const U: i8x1 = i8x1(13);
19+
const V: i8x1 = unsafe { simd_insert(U, 0_u32, 42_i8) };
20+
const X0: i8 = V.0;
21+
const Y0: i8 = unsafe { simd_extract(V, 0) };
22+
assert_eq!(X0, 42);
23+
assert_eq!(Y0, 42);
24+
}
25+
{
26+
const U: u16x2 = u16x2(13, 14);
27+
const V: u16x2 = unsafe { simd_insert(U, 1_u32, 42_u16) };
28+
const X0: u16 = V.0;
29+
const X1: u16 = V.1;
30+
const Y0: u16 = unsafe { simd_extract(V, 0) };
31+
const Y1: u16 = unsafe { simd_extract(V, 1) };
32+
assert_eq!(X0, 13);
33+
assert_eq!(X1, 42);
34+
assert_eq!(Y0, 13);
35+
assert_eq!(Y1, 42);
36+
}
37+
{
38+
const U: f32x3 = f32x3(13., 14., 15.);
39+
const V: f32x3 = unsafe { simd_insert(U, 1_u32, 42_f32) };
40+
const X0: f32 = V.0;
41+
const X1: f32 = V.1;
42+
const X2: f32 = V.2;
43+
const Y0: f32 = unsafe { simd_extract(V, 0) };
44+
const Y1: f32 = unsafe { simd_extract(V, 1) };
45+
const Y2: f32 = unsafe { simd_extract(V, 2) };
46+
assert_eq!(X0, 13.);
47+
assert_eq!(X1, 42.);
48+
assert_eq!(X2, 15.);
49+
assert_eq!(Y0, 13.);
50+
assert_eq!(Y1, 42.);
51+
assert_eq!(Y2, 15.);
52+
}
53+
}

0 commit comments

Comments
 (0)