Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup Miri SIMD intrinsics #66468

Merged
merged 5 commits into from
Nov 21, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/librustc/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// SIMD vector types.
ty::Adt(def, ..) if def.repr.simd() => {
let element = self.layout_of(ty.simd_type(tcx))?;
let count = ty.simd_size(tcx) as u64;
let count = ty.simd_size(tcx);
assert!(count > 0);
let scalar = match element.abi {
Abi::Scalar(ref scalar) => scalar.clone(),
Expand Down
20 changes: 15 additions & 5 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1814,20 +1814,30 @@ impl<'tcx> TyS<'tcx> {

pub fn simd_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self.kind {
Adt(def, substs) => {
def.non_enum_variant().fields[0].ty(tcx, substs)
}
Adt(def, substs) => def.non_enum_variant().fields[0].ty(tcx, substs),
_ => bug!("simd_type called on invalid type")
}
}

pub fn simd_size(&self, _cx: TyCtxt<'_>) -> usize {
pub fn simd_size(&self, _tcx: TyCtxt<'tcx>) -> u64 {
// Parameter currently unused, but probably needed in the future to
// allow `#[repr(simd)] struct Simd<T, const N: usize>([T; N]);`.
match self.kind {
Adt(def, _) => def.non_enum_variant().fields.len(),
Adt(def, _) => def.non_enum_variant().fields.len() as u64,
_ => bug!("simd_size called on invalid type")
}
}

pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
match self.kind {
Adt(def, substs) => {
let variant = def.non_enum_variant();
(variant.fields.len() as u64, variant.fields[0].ty(tcx, substs))
}
_ => bug!("simd_size_and_type called on invalid type")
}
}

#[inline]
pub fn is_region_ptr(&self) -> bool {
match self.kind {
Expand Down
22 changes: 13 additions & 9 deletions src/librustc_codegen_llvm/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use syntax_pos::Span;

use std::cmp::Ordering;
use std::{iter, i128, u128};
use std::convert::TryFrom;

fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> {
let llvm_name = match name {
Expand Down Expand Up @@ -1105,8 +1106,8 @@ fn generic_simd_intrinsic(
let m_len = match in_ty.kind {
// Note that this `.unwrap()` crashes for isize/usize, that's sort
// of intentional as there's not currently a use case for that.
ty::Int(i) => i.bit_width().unwrap(),
ty::Uint(i) => i.bit_width().unwrap(),
ty::Int(i) => i.bit_width().unwrap() as u64,
ty::Uint(i) => i.bit_width().unwrap() as u64,
_ => return_error!("`{}` is not an integral type", in_ty),
};
require_simd!(arg_tys[1], "argument");
Expand All @@ -1116,7 +1117,7 @@ fn generic_simd_intrinsic(
m_len, v_len
);
let i1 = bx.type_i1();
let i1xn = bx.type_vector(i1, m_len as u64);
let i1xn = bx.type_vector(i1, m_len);
let m_i1s = bx.bitcast(args[0].immediate(), i1xn);
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
}
Expand Down Expand Up @@ -1166,7 +1167,7 @@ fn generic_simd_intrinsic(
require_simd!(ret_ty, "return");

let out_len = ret_ty.simd_size(tcx);
require!(out_len == n,
require!(out_len == n as u64,
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
"expected return type of length {}, found `{}` with length {}",
n, ret_ty, out_len);
require!(in_elem == ret_ty.simd_type(tcx),
Expand Down Expand Up @@ -1251,7 +1252,7 @@ fn generic_simd_intrinsic(
// trailing bits.
let expected_int_bits = in_len.max(8);
match ret_ty.kind {
ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (),
ty::Uint(i) if i.bit_width() == Some(expected_int_bits as usize) => (),
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
_ => return_error!(
"bitmask `{}`, expected `u{}`",
ret_ty, expected_int_bits
Expand All @@ -1276,7 +1277,8 @@ fn generic_simd_intrinsic(

// Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position.
let shift_indices = vec![
bx.cx.const_int(bx.type_ix(in_elem_bitwidth as _), (in_elem_bitwidth - 1) as _); in_len
bx.cx.const_int(bx.type_ix(in_elem_bitwidth as _), (in_elem_bitwidth - 1) as _);
in_len as _
];
let i_xn_msb = bx.lshr(i_xn, bx.const_vector(shift_indices.as_slice()));
// Truncate vector to an <i1 x N>
Expand All @@ -1291,7 +1293,7 @@ fn generic_simd_intrinsic(
name: &str,
in_elem: &::rustc::ty::TyS<'_>,
in_ty: &::rustc::ty::TyS<'_>,
in_len: usize,
in_len: u64,
bx: &mut Builder<'a, 'll, 'tcx>,
span: Span,
args: &[OperandRef<'tcx, &'ll Value>],
Expand Down Expand Up @@ -1506,11 +1508,12 @@ fn generic_simd_intrinsic(
// Truncate the mask vector to a vector of i1s:
let (mask, mask_ty) = {
let i1 = bx.type_i1();
let i1xn = bx.type_vector(i1, in_len as u64);
let i1xn = bx.type_vector(i1, in_len);
(bx.trunc(args[2].immediate(), i1xn), i1xn)
};

// Type of the vector of pointers:
let in_len = usize::try_from(in_len).unwrap();
let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count);
let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count);
RalfJung marked this conversation as resolved.
Show resolved Hide resolved

Expand Down Expand Up @@ -1606,13 +1609,14 @@ fn generic_simd_intrinsic(
// Truncate the mask vector to a vector of i1s:
let (mask, mask_ty) = {
let i1 = bx.type_i1();
let i1xn = bx.type_vector(i1, in_len as u64);
let i1xn = bx.type_vector(i1, in_len);
(bx.trunc(args[2].immediate(), i1xn), i1xn)
};

let ret_t = bx.type_void();

// Type of the vector of pointers:
let in_len = usize::try_from(in_len).unwrap();
let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count);
let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count);

Expand Down
18 changes: 9 additions & 9 deletions src/librustc_mir/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.copy_op_transmute(args[0], dest)?;
}
"simd_insert" => {
let index = self.read_scalar(args[1])?.to_u32()? as u64;
let scalar = args[2];
let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
let elem = args[2];
let input = args[0];
let (len, e_ty) = self.read_vector_ty(input);
let (len, e_ty) = input.layout.ty.simd_size_and_type(self.tcx.tcx);
assert!(
index < len,
"Index `{}` must be in bounds of vector type `{}`: `[0, {})`",
Expand All @@ -317,24 +317,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
dest.layout.ty, input.layout.ty
);
assert_eq!(
scalar.layout.ty, e_ty,
"Scalar type `{}` must match vector element type `{}`",
scalar.layout.ty, e_ty
elem.layout.ty, e_ty,
"Scalar element type `{}` must match vector element type `{}`",
elem.layout.ty, e_ty
);

for i in 0..len {
let place = self.place_field(dest, i)?;
let value = if i == index {
scalar
elem
} else {
self.operand_field(input, i)?
};
self.copy_op(value, place)?;
}
}
"simd_extract" => {
let index = self.read_scalar(args[1])?.to_u32()? as _;
let (len, e_ty) = self.read_vector_ty(args[0]);
let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
let (len, e_ty) = args[0].layout.ty.simd_size_and_type(self.tcx.tcx);
assert!(
index < len,
"index `{}` is out-of-bounds of vector type `{}` with length `{}`",
Expand Down
11 changes: 0 additions & 11 deletions src/librustc_mir/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,17 +315,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}

/// Read vector length and element type
pub fn read_vector_ty(
&self, op: OpTy<'tcx, M::PointerTag>
) -> (u64, &rustc::ty::TyS<'tcx>) {
if let layout::Abi::Vector { .. } = op.layout.abi {
(op.layout.ty.simd_size(*self.tcx) as _, op.layout.ty.simd_type(*self.tcx))
} else {
bug!("Type `{}` is not a SIMD vector type", op.layout.ty)
}
}

/// Read a scalar from a place
pub fn read_scalar(
&self,
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_mir/interpret/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

match instance.def {
ty::InstanceDef::Intrinsic(..) => {
if caller_abi != Abi::RustIntrinsic && caller_abi != Abi::PlatformIntrinsic {
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
throw_ub_format!("Rust intrinsic called with an ABI other than \
`RustIntrinsic` and `PlatformIntrinsic`.");
}

let old_stack = self.cur_frame();
let old_bb = self.frame().block;
M::call_intrinsic(self, span, instance, args, dest, ret, unwind)?;
Expand Down