diff options
| author | bors <bors@rust-lang.org> | 2019-01-24 13:11:06 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-01-24 13:11:06 +0000 |
| commit | 095b44c83b540bb4dbf74be1cae604f4bae87989 (patch) | |
| tree | 660a01091b2a50604735d6d3ddaa862dadb238c9 /src/librustc_codegen_llvm | |
| parent | f23b63cbbf8d92deac6b3c39746d3b85d3e838af (diff) | |
| parent | 785f529d6e91b787d94b44726a5d6018e8fe181b (diff) | |
| download | rust-095b44c83b540bb4dbf74be1cae604f4bae87989.tar.gz rust-095b44c83b540bb4dbf74be1cae604f4bae87989.zip | |
Auto merge of #57269 - gnzlbg:simd_bitmask, r=rkruppe
Add intrinsic to create an integer bitmask from a vector mask This PR adds a new simd intrinsic: `simd_bitmask(vector) -> unsigned integer` that creates an integer bitmask from a vector mask by extracting one bit of each vector lane. This is required to implement: https://github.com/rust-lang-nursery/packed_simd/issues/166 . EDIT: the reason we need an intrinsics for this is that we have to truncate the vector lanes to an `<i1 x N>` vector, and then bitcast that to an `iN` integer (while making sure that we only materialize `i8`, ... , `i64` - that is, no `i1`, `i2`, `i4`, types), and we can't do any of that in a Rust library. r? @rkruppe
Diffstat (limited to 'src/librustc_codegen_llvm')
| -rw-r--r-- | src/librustc_codegen_llvm/intrinsic.rs | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index eeb6a64164e..201b1684fb9 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1167,6 +1167,52 @@ fn generic_simd_intrinsic( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } + if name == "simd_bitmask" { + // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a + // vector mask and returns an unsigned integer containing the most + // significant bit (MSB) of each lane. + use rustc_target::abi::HasDataLayout; + + // If the vector has less than 8 lanes, an u8 is returned with zeroed + // trailing bits. + let expected_int_bits = in_len.max(8); + match ret_ty.sty { + ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (), + _ => return_error!( + "bitmask `{}`, expected `u{}`", + ret_ty, expected_int_bits + ), + } + + // Integer vector <i{in_bitwidth} x in_len>: + let (i_xn, in_elem_bitwidth) = match in_elem.sty { + ty::Int(i) => ( + args[0].immediate(), + i.bit_width().unwrap_or(bx.data_layout().pointer_size.bits() as _) + ), + ty::Uint(i) => ( + args[0].immediate(), + i.bit_width().unwrap_or(bx.data_layout().pointer_size.bits() as _) + ), + _ => return_error!( + "vector argument `{}`'s element type `{}`, expected integer element type", + in_ty, in_elem + ), + }; + + // 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 + ]; + let i_xn_msb = bx.lshr(i_xn, bx.const_vector(shift_indices.as_slice())); + // Truncate vector to an <i1 x N> + let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len as _)); + // Bitcast <i1 x N> to iN: + let i_ = bx.bitcast(i1xn, bx.type_ix(in_len as _)); + // Zero-extend iN to the bitmask type: + return Ok(bx.zext(i_, bx.type_ix(expected_int_bits as _))); + } + fn simd_simple_float_intrinsic( name: &str, in_elem: &::rustc::ty::TyS, |
