Skip to content

Commit 0307e40

Browse files
committed
Auto merge of rust-lang#130215 - RalfJung:interpret-simd, r=compiler-errors
interpret: simplify SIMD type handling This is possible as a follow-up to rust-lang#129403
2 parents 473ae00 + e2bc16c commit 0307e40

File tree

15 files changed

+190
-199
lines changed

15 files changed

+190
-199
lines changed

Diff for: compiler/rustc_const_eval/src/interpret/intrinsics.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
384384
sym::simd_insert => {
385385
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
386386
let elem = &args[2];
387-
let (input, input_len) = self.operand_to_simd(&args[0])?;
388-
let (dest, dest_len) = self.mplace_to_simd(dest)?;
387+
let (input, input_len) = self.project_to_simd(&args[0])?;
388+
let (dest, dest_len) = self.project_to_simd(dest)?;
389389
assert_eq!(input_len, dest_len, "Return vector length must match input length");
390390
// Bounds are not checked by typeck so we have to do it ourselves.
391391
if index >= input_len {
@@ -406,7 +406,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
406406
}
407407
sym::simd_extract => {
408408
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
409-
let (input, input_len) = self.operand_to_simd(&args[0])?;
409+
let (input, input_len) = self.project_to_simd(&args[0])?;
410410
// Bounds are not checked by typeck so we have to do it ourselves.
411411
if index >= input_len {
412412
throw_ub_format!(

Diff for: compiler/rustc_const_eval/src/interpret/operand.rs

-24
Original file line numberDiff line numberDiff line change
@@ -681,30 +681,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
681681
Ok(str)
682682
}
683683

684-
/// Converts a repr(simd) operand into an operand where `place_index` accesses the SIMD elements.
685-
/// Also returns the number of elements.
686-
///
687-
/// Can (but does not always) trigger UB if `op` is uninitialized.
688-
pub fn operand_to_simd(
689-
&self,
690-
op: &OpTy<'tcx, M::Provenance>,
691-
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> {
692-
// Basically we just transmute this place into an array following simd_size_and_type.
693-
// This only works in memory, but repr(simd) types should never be immediates anyway.
694-
assert!(op.layout.ty.is_simd());
695-
match op.as_mplace_or_imm() {
696-
Left(mplace) => self.mplace_to_simd(&mplace),
697-
Right(imm) => match *imm {
698-
Immediate::Uninit => {
699-
throw_ub!(InvalidUninitBytes(None))
700-
}
701-
Immediate::Scalar(..) | Immediate::ScalarPair(..) => {
702-
bug!("arrays/slices can never have Scalar/ScalarPair layout")
703-
}
704-
},
705-
}
706-
}
707-
708684
/// Read from a local of the current frame.
709685
/// Will not access memory, instead an indirect `Operand` is returned.
710686
///

Diff for: compiler/rustc_const_eval/src/interpret/place.rs

+22-23
Original file line numberDiff line numberDiff line change
@@ -377,13 +377,15 @@ where
377377
Prov: Provenance,
378378
M: Machine<'tcx, Provenance = Prov>,
379379
{
380-
pub fn ptr_with_meta_to_mplace(
380+
fn ptr_with_meta_to_mplace(
381381
&self,
382382
ptr: Pointer<Option<M::Provenance>>,
383383
meta: MemPlaceMeta<M::Provenance>,
384384
layout: TyAndLayout<'tcx>,
385+
unaligned: bool,
385386
) -> MPlaceTy<'tcx, M::Provenance> {
386-
let misaligned = self.is_ptr_misaligned(ptr, layout.align.abi);
387+
let misaligned =
388+
if unaligned { None } else { self.is_ptr_misaligned(ptr, layout.align.abi) };
387389
MPlaceTy { mplace: MemPlace { ptr, meta, misaligned }, layout }
388390
}
389391

@@ -393,7 +395,16 @@ where
393395
layout: TyAndLayout<'tcx>,
394396
) -> MPlaceTy<'tcx, M::Provenance> {
395397
assert!(layout.is_sized());
396-
self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout)
398+
self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout, /*unaligned*/ false)
399+
}
400+
401+
pub fn ptr_to_mplace_unaligned(
402+
&self,
403+
ptr: Pointer<Option<M::Provenance>>,
404+
layout: TyAndLayout<'tcx>,
405+
) -> MPlaceTy<'tcx, M::Provenance> {
406+
assert!(layout.is_sized());
407+
self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout, /*unaligned*/ true)
397408
}
398409

399410
/// Take a value, which represents a (thin or wide) reference, and make it a place.
@@ -414,7 +425,7 @@ where
414425
// `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced;
415426
// we hence can't call `size_and_align_of` since that asserts more validity than we want.
416427
let ptr = ptr.to_pointer(self)?;
417-
Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout))
428+
Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false))
418429
}
419430

420431
/// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space.
@@ -484,23 +495,6 @@ where
484495
Ok(a)
485496
}
486497

487-
/// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements.
488-
/// Also returns the number of elements.
489-
pub fn mplace_to_simd(
490-
&self,
491-
mplace: &MPlaceTy<'tcx, M::Provenance>,
492-
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> {
493-
// Basically we want to transmute this place into an array following simd_size_and_type.
494-
let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx);
495-
// Some SIMD types have padding, so `len` many `e_ty` does not cover the entire place.
496-
// Therefore we cannot transmute, and instead we project at offset 0, which side-steps
497-
// the size check.
498-
let array_layout = self.layout_of(Ty::new_array(self.tcx.tcx, e_ty, len))?;
499-
assert!(array_layout.size <= mplace.layout.size);
500-
let mplace = mplace.offset(Size::ZERO, array_layout, self)?;
501-
Ok((mplace, len))
502-
}
503-
504498
/// Turn a local in the current frame into a place.
505499
pub fn local_to_place(
506500
&self,
@@ -986,7 +980,7 @@ where
986980
span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known")
987981
};
988982
let ptr = self.allocate_ptr(size, align, kind)?;
989-
Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout))
983+
Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false))
990984
}
991985

992986
pub fn allocate(
@@ -1021,7 +1015,12 @@ where
10211015
};
10221016
let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self);
10231017
let layout = self.layout_of(self.tcx.types.str_).unwrap();
1024-
Ok(self.ptr_with_meta_to_mplace(ptr.into(), MemPlaceMeta::Meta(meta), layout))
1018+
Ok(self.ptr_with_meta_to_mplace(
1019+
ptr.into(),
1020+
MemPlaceMeta::Meta(meta),
1021+
layout,
1022+
/*unaligned*/ false,
1023+
))
10251024
}
10261025

10271026
pub fn raw_const_to_mplace(

Diff for: compiler/rustc_const_eval/src/interpret/projection.rs

+13
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,19 @@ where
244244
base.offset(offset, field_layout, self)
245245
}
246246

247+
/// Converts a repr(simd) value into an array of the right size, such that `project_index`
248+
/// accesses the SIMD elements. Also returns the number of elements.
249+
pub fn project_to_simd<P: Projectable<'tcx, M::Provenance>>(
250+
&self,
251+
base: &P,
252+
) -> InterpResult<'tcx, (P, u64)> {
253+
assert!(base.layout().ty.ty_adt_def().unwrap().repr().simd());
254+
// SIMD types must be newtypes around arrays, so all we have to do is project to their only field.
255+
let array = self.project_field(base, 0)?;
256+
let len = array.len(self)?;
257+
Ok((array, len))
258+
}
259+
247260
fn project_constant_index<P: Projectable<'tcx, M::Provenance>>(
248261
&self,
249262
base: &P,

Diff for: compiler/rustc_const_eval/src/interpret/util.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_middle::ty::{
99
};
1010
use tracing::debug;
1111

12-
use super::{throw_inval, InterpCx, MPlaceTy, MemPlaceMeta, MemoryKind};
12+
use super::{throw_inval, InterpCx, MPlaceTy, MemoryKind};
1313
use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult};
1414

1515
/// Checks whether a type contains generic parameters which must be instantiated.
@@ -103,5 +103,5 @@ pub(crate) fn create_static_alloc<'tcx>(
103103
assert_eq!(ecx.machine.static_root_ids, None);
104104
ecx.machine.static_root_ids = Some((alloc_id, static_def_id));
105105
assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none());
106-
Ok(ecx.ptr_with_meta_to_mplace(Pointer::from(alloc_id).into(), MemPlaceMeta::None, layout))
106+
Ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout))
107107
}

Diff for: src/tools/miri/src/intrinsics/simd.rs

+41-41
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
5050
| "bitreverse"
5151
=> {
5252
let [op] = check_arg_count(args)?;
53-
let (op, op_len) = this.operand_to_simd(op)?;
54-
let (dest, dest_len) = this.mplace_to_simd(dest)?;
53+
let (op, op_len) = this.project_to_simd(op)?;
54+
let (dest, dest_len) = this.project_to_simd(dest)?;
5555

5656
assert_eq!(dest_len, op_len);
5757

@@ -200,9 +200,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
200200
use mir::BinOp;
201201

202202
let [left, right] = check_arg_count(args)?;
203-
let (left, left_len) = this.operand_to_simd(left)?;
204-
let (right, right_len) = this.operand_to_simd(right)?;
205-
let (dest, dest_len) = this.mplace_to_simd(dest)?;
203+
let (left, left_len) = this.project_to_simd(left)?;
204+
let (right, right_len) = this.project_to_simd(right)?;
205+
let (dest, dest_len) = this.project_to_simd(dest)?;
206206

207207
assert_eq!(dest_len, left_len);
208208
assert_eq!(dest_len, right_len);
@@ -291,10 +291,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
291291
}
292292
"fma" => {
293293
let [a, b, c] = check_arg_count(args)?;
294-
let (a, a_len) = this.operand_to_simd(a)?;
295-
let (b, b_len) = this.operand_to_simd(b)?;
296-
let (c, c_len) = this.operand_to_simd(c)?;
297-
let (dest, dest_len) = this.mplace_to_simd(dest)?;
294+
let (a, a_len) = this.project_to_simd(a)?;
295+
let (b, b_len) = this.project_to_simd(b)?;
296+
let (c, c_len) = this.project_to_simd(c)?;
297+
let (dest, dest_len) = this.project_to_simd(dest)?;
298298

299299
assert_eq!(dest_len, a_len);
300300
assert_eq!(dest_len, b_len);
@@ -345,7 +345,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
345345
use mir::BinOp;
346346

347347
let [op] = check_arg_count(args)?;
348-
let (op, op_len) = this.operand_to_simd(op)?;
348+
let (op, op_len) = this.project_to_simd(op)?;
349349

350350
let imm_from_bool =
351351
|b| ImmTy::from_scalar(Scalar::from_bool(b), this.machine.layouts.bool);
@@ -408,7 +408,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
408408
use mir::BinOp;
409409

410410
let [op, init] = check_arg_count(args)?;
411-
let (op, op_len) = this.operand_to_simd(op)?;
411+
let (op, op_len) = this.project_to_simd(op)?;
412412
let init = this.read_immediate(init)?;
413413

414414
let mir_op = match intrinsic_name {
@@ -426,10 +426,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
426426
}
427427
"select" => {
428428
let [mask, yes, no] = check_arg_count(args)?;
429-
let (mask, mask_len) = this.operand_to_simd(mask)?;
430-
let (yes, yes_len) = this.operand_to_simd(yes)?;
431-
let (no, no_len) = this.operand_to_simd(no)?;
432-
let (dest, dest_len) = this.mplace_to_simd(dest)?;
429+
let (mask, mask_len) = this.project_to_simd(mask)?;
430+
let (yes, yes_len) = this.project_to_simd(yes)?;
431+
let (no, no_len) = this.project_to_simd(no)?;
432+
let (dest, dest_len) = this.project_to_simd(dest)?;
433433

434434
assert_eq!(dest_len, mask_len);
435435
assert_eq!(dest_len, yes_len);
@@ -448,9 +448,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
448448
// Variant of `select` that takes a bitmask rather than a "vector of bool".
449449
"select_bitmask" => {
450450
let [mask, yes, no] = check_arg_count(args)?;
451-
let (yes, yes_len) = this.operand_to_simd(yes)?;
452-
let (no, no_len) = this.operand_to_simd(no)?;
453-
let (dest, dest_len) = this.mplace_to_simd(dest)?;
451+
let (yes, yes_len) = this.project_to_simd(yes)?;
452+
let (no, no_len) = this.project_to_simd(no)?;
453+
let (dest, dest_len) = this.project_to_simd(dest)?;
454454
let bitmask_len = dest_len.next_multiple_of(8);
455455
if bitmask_len > 64 {
456456
throw_unsup_format!(
@@ -522,7 +522,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
522522
// Converts a "vector of bool" into a bitmask.
523523
"bitmask" => {
524524
let [op] = check_arg_count(args)?;
525-
let (op, op_len) = this.operand_to_simd(op)?;
525+
let (op, op_len) = this.project_to_simd(op)?;
526526
let bitmask_len = op_len.next_multiple_of(8);
527527
if bitmask_len > 64 {
528528
throw_unsup_format!(
@@ -570,8 +570,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
570570
}
571571
"cast" | "as" | "cast_ptr" | "expose_provenance" | "with_exposed_provenance" => {
572572
let [op] = check_arg_count(args)?;
573-
let (op, op_len) = this.operand_to_simd(op)?;
574-
let (dest, dest_len) = this.mplace_to_simd(dest)?;
573+
let (op, op_len) = this.project_to_simd(op)?;
574+
let (dest, dest_len) = this.project_to_simd(dest)?;
575575

576576
assert_eq!(dest_len, op_len);
577577

@@ -627,9 +627,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
627627
}
628628
"shuffle_generic" => {
629629
let [left, right] = check_arg_count(args)?;
630-
let (left, left_len) = this.operand_to_simd(left)?;
631-
let (right, right_len) = this.operand_to_simd(right)?;
632-
let (dest, dest_len) = this.mplace_to_simd(dest)?;
630+
let (left, left_len) = this.project_to_simd(left)?;
631+
let (right, right_len) = this.project_to_simd(right)?;
632+
let (dest, dest_len) = this.project_to_simd(dest)?;
633633

634634
let index = generic_args[2]
635635
.expect_const()
@@ -662,15 +662,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
662662
}
663663
"shuffle" => {
664664
let [left, right, index] = check_arg_count(args)?;
665-
let (left, left_len) = this.operand_to_simd(left)?;
666-
let (right, right_len) = this.operand_to_simd(right)?;
667-
let (dest, dest_len) = this.mplace_to_simd(dest)?;
665+
let (left, left_len) = this.project_to_simd(left)?;
666+
let (right, right_len) = this.project_to_simd(right)?;
667+
let (dest, dest_len) = this.project_to_simd(dest)?;
668668

669669
// `index` is an array or a SIMD type
670670
let (index, index_len) = match index.layout.ty.kind() {
671671
// FIXME: remove this once `index` must always be a SIMD vector.
672-
ty::Array(..) => (index.assert_mem_place(), index.len(this)?),
673-
_ => this.operand_to_simd(index)?,
672+
ty::Array(..) => (index.clone(), index.len(this)?),
673+
_ => this.project_to_simd(index)?,
674674
};
675675

676676
assert_eq!(left_len, right_len);
@@ -699,10 +699,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
699699
}
700700
"gather" => {
701701
let [passthru, ptrs, mask] = check_arg_count(args)?;
702-
let (passthru, passthru_len) = this.operand_to_simd(passthru)?;
703-
let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?;
704-
let (mask, mask_len) = this.operand_to_simd(mask)?;
705-
let (dest, dest_len) = this.mplace_to_simd(dest)?;
702+
let (passthru, passthru_len) = this.project_to_simd(passthru)?;
703+
let (ptrs, ptrs_len) = this.project_to_simd(ptrs)?;
704+
let (mask, mask_len) = this.project_to_simd(mask)?;
705+
let (dest, dest_len) = this.project_to_simd(dest)?;
706706

707707
assert_eq!(dest_len, passthru_len);
708708
assert_eq!(dest_len, ptrs_len);
@@ -725,9 +725,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
725725
}
726726
"scatter" => {
727727
let [value, ptrs, mask] = check_arg_count(args)?;
728-
let (value, value_len) = this.operand_to_simd(value)?;
729-
let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?;
730-
let (mask, mask_len) = this.operand_to_simd(mask)?;
728+
let (value, value_len) = this.project_to_simd(value)?;
729+
let (ptrs, ptrs_len) = this.project_to_simd(ptrs)?;
730+
let (mask, mask_len) = this.project_to_simd(mask)?;
731731

732732
assert_eq!(ptrs_len, value_len);
733733
assert_eq!(ptrs_len, mask_len);
@@ -745,10 +745,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
745745
}
746746
"masked_load" => {
747747
let [mask, ptr, default] = check_arg_count(args)?;
748-
let (mask, mask_len) = this.operand_to_simd(mask)?;
748+
let (mask, mask_len) = this.project_to_simd(mask)?;
749749
let ptr = this.read_pointer(ptr)?;
750-
let (default, default_len) = this.operand_to_simd(default)?;
751-
let (dest, dest_len) = this.mplace_to_simd(dest)?;
750+
let (default, default_len) = this.project_to_simd(default)?;
751+
let (dest, dest_len) = this.project_to_simd(dest)?;
752752

753753
assert_eq!(dest_len, mask_len);
754754
assert_eq!(dest_len, default_len);
@@ -772,9 +772,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
772772
}
773773
"masked_store" => {
774774
let [mask, ptr, vals] = check_arg_count(args)?;
775-
let (mask, mask_len) = this.operand_to_simd(mask)?;
775+
let (mask, mask_len) = this.project_to_simd(mask)?;
776776
let ptr = this.read_pointer(ptr)?;
777-
let (vals, vals_len) = this.operand_to_simd(vals)?;
777+
let (vals, vals_len) = this.project_to_simd(vals)?;
778778

779779
assert_eq!(mask_len, vals_len);
780780

Diff for: src/tools/miri/src/shims/foreign_items.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -903,8 +903,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
903903
name if name.starts_with("llvm.ctpop.v") => {
904904
let [op] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
905905

906-
let (op, op_len) = this.operand_to_simd(op)?;
907-
let (dest, dest_len) = this.mplace_to_simd(dest)?;
906+
let (op, op_len) = this.project_to_simd(op)?;
907+
let (dest, dest_len) = this.project_to_simd(dest)?;
908908

909909
assert_eq!(dest_len, op_len);
910910

0 commit comments

Comments
 (0)