Change:
As far as I can tell this bug only exists when performing a simd gather instruction on a slice of usize. If the slice is instead typed as u64 or u32 this code succeeds. : </p</details<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
Here we attempt to invoke on Uints and Ints, which may be Usize or Isize, which do not have a specified bit width and so return the None value which we gleefully unwrap. We can invoke instead in these cases, OR change this to use the mentioned LLVM bindings (though any such effort should really reference a tag in instead). Though: I am surprised that these integers are not already normalized at this point.
I'm happy to work on this. claim
I found this comment in : It might be intentional, but maybe an ICE isn't the best way to go. Should some kind of error be in? Otherwise I'm not really sure what width it should be normalised to. I did think the most obvious would be the target arch's width but I'm not really sure how to get that within this function since there doesn't seem to be a target specification within scope.
I believe that comment applies only for handling . I do not see how the reasoning expressed there applies to or , as it is (admittedly unusual) but valid to want to gather or scatter slices of those. Ideally some refactoring could happen to make it clearer such reasoning is isolated from the rest of these intrinsics. cc
Yes, that only applies to bitmasks, which cannot be /.
And it should be normalized to the target width, yes. There should be relevant functions, types, and methods for doing so either already present in the imports from or you can find them elsewhere in . I believe you want to be calling which will yield and then all the information should be there. Feel free to r? me on your PR, including a draft.
Since there is a bit of chatter here on the use cases for performing a scatter or gather for indexes, I can give a little bit of context, since I do think it is somewhat informative. In this case I am working on a columnar store. You can kind of think of the use case as a secondary index over columnar data. For just a single primary index, you have a list of row_ids Simd<usize, LANESand you can perform a simd gather instruction to get all of the values at those indexes. However, if you have a secondary index the simd gather from that secondary index needs to produce a Simd<usize, LANES, so that can be passed directly into the second of the gather functions over the primary keys. In this way you go from needed 2*LANES loads to perform a secondary index lookup over data to only needing 2 simd operations. Alternatively it would be nice if the Simd libraries were updated to perform gathers using indexes as Simd<u32, LANESor Simd<u64, LANES. That would dodge this issue altogether and it would mean less copies in our columnar store. Many times columnar stores you keep offsets as u32 (or even smaller) to keep things compressed. And it is nice to be able to act directly on those indices rather than performing intermediate conversions to usize.

Discussion:
use rustc_middle::{bug, span_bug}; use rustc_span::{sym, symbol::kw, Span, Symbol}; use rustc_target::abi::{self, HasDataLayout, Primitive}; <del> use rustc_target::spec::PanicStrategy; </del> <ins> use rustc_target::spec::{HasTargetSpec, PanicStrategy}; </ins> use std::cmp::Ordering; use std::iter;

// FIXME: use: //  https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182 //  https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 <del> fn llvm_vector_str(elem_ty: Ty<'_>, vec_len: u64, no_pointers: usize) -> String { </del> <ins> fn llvm_vector_str( elem_ty: Ty<'_>, vec_len: u64, no_pointers: usize, bx: &Builder<'a, 'll, 'tcx>, ) -> String { </ins> let p0s: String = "p0".repeat(no_pointers); match *elem_ty.kind() { <del> ty::Int(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), ty::Uint(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), </del> <ins> ty::Int(v) => format!( "v{}{}i{}", vec_len, p0s, // Normalize to prevent crash if v: IntTy::Isize v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() ), ty::Uint(v) => format!( "v{}{}i{}", vec_len, p0s, // Normalize to prevent crash if v: UIntTy::Usize v.normalize(bx.target_spec().pointer_width).bit_width().unwrap() ), </ins> ty::Float(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()), _ => unreachable!(), }

// Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count); <del> let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); </del> <ins> let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx); </ins> // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1); <del> let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); </del> <ins> let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx); </ins> let llvm_intrinsic = format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);

// Type of the vector of pointers: let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count); <del> let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); </del> <ins> let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx); </ins> // Type of the vector of elements: let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1); <del> let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); </del> <ins> let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx); </ins> let llvm_intrinsic = format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);

<ins> // run-pass // Test that simd gather instructions on slice of usize don't cause crash // See issue #89183 - https://github.com/rust-lang/rust/issues/89193 #![feature(repr_simd, platform_intrinsics)] #![allow(non_camel_case_types)] #[repr(simd)] #[derive(Copy, Clone, PartialEq, Debug)] struct x4<T>(pub T, pub T, pub T, pub T); extern "platform-intrinsic" { fn simd_gather<T, U, V>(x: T, y: U, z: V) -> T; } fn main() { let x: [usize; 4] = [10, 11, 12, 13]; let default = x4(0_usize, 1, 2, 3); let mask = x4(1_i32, 1, 1, 1); let expected = x4(10_usize, 11, 12, 13); unsafe { let pointer = &x[0] as *const usize; let pointers =  x4( pointer.offset(0) as *const usize, pointer.offset(1), pointer.offset(2), pointer.offset(3) ); let result = simd_gather(default, pointers, mask); assert_eq!(result, expected); } // and again for isize let x: [isize; 4] = [10, 11, 12, 13]; let default = x4(0_isize, 1, 2, 3); let expected = x4(10_isize, 11, 12, 13); unsafe { let pointer = &x[0] as *const isize; let pointers =  x4( pointer.offset(0) as *const isize, pointer.offset(1), pointer.offset(2), pointer.offset(3) ); let result = simd_gather(default, pointers, mask); assert_eq!(result, expected); } } </ins>