|
| 1 | +use std::convert::TryInto; |
1 | 2 | use std::iter;
|
2 | 3 |
|
3 | 4 | use log::trace;
|
4 | 5 |
|
5 | 6 | use rustc_apfloat::{Float, Round};
|
6 | 7 | use rustc_middle::ty::layout::{HasParamEnv, IntegerExt, LayoutOf};
|
7 | 8 | use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy};
|
8 |
| -use rustc_target::abi::{Align, Integer}; |
| 9 | +use rustc_target::abi::{Align, Endian, HasDataLayout, Integer, Size}; |
9 | 10 |
|
10 | 11 | use crate::*;
|
11 |
| -use helpers::{bool_to_simd_element, check_arg_count, simd_element_to_bool}; |
| 12 | +use helpers::check_arg_count; |
12 | 13 |
|
13 | 14 | pub enum AtomicOp {
|
14 | 15 | MirOp(mir::BinOp, bool),
|
@@ -663,6 +664,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
663 | 664 | this.write_immediate(*val, &dest.into())?;
|
664 | 665 | }
|
665 | 666 | }
|
| 667 | + "simd_select_bitmask" => { |
| 668 | + let &[ref mask, ref yes, ref no] = check_arg_count(args)?; |
| 669 | + let (yes, yes_len) = this.operand_to_simd(yes)?; |
| 670 | + let (no, no_len) = this.operand_to_simd(no)?; |
| 671 | + let (dest, dest_len) = this.place_to_simd(dest)?; |
| 672 | + |
| 673 | + assert!(mask.layout.ty.is_integral()); |
| 674 | + assert_eq!(dest_len.max(8), mask.layout.size.bits()); |
| 675 | + assert!(dest_len <= 64); |
| 676 | + assert_eq!(dest_len, yes_len); |
| 677 | + assert_eq!(dest_len, no_len); |
| 678 | + |
| 679 | + let mask: u64 = this |
| 680 | + .read_scalar(mask)? |
| 681 | + .check_init()? |
| 682 | + .to_bits(mask.layout.size)? |
| 683 | + .try_into() |
| 684 | + .unwrap(); |
| 685 | + for i in 0..dest_len { |
| 686 | + let mask = |
| 687 | + mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); |
| 688 | + let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; |
| 689 | + let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; |
| 690 | + let dest = this.mplace_index(&dest, i)?; |
| 691 | + |
| 692 | + let val = if mask != 0 { yes } else { no }; |
| 693 | + this.write_immediate(*val, &dest.into())?; |
| 694 | + } |
| 695 | + } |
666 | 696 | #[rustfmt::skip]
|
667 | 697 | "simd_cast" | "simd_as" => {
|
668 | 698 | let &[ref op] = check_arg_count(args)?;
|
@@ -787,6 +817,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
787 | 817 | }
|
788 | 818 | }
|
789 | 819 | }
|
| 820 | + "simd_bitmask" => { |
| 821 | + let &[ref op] = check_arg_count(args)?; |
| 822 | + let (op, op_len) = this.operand_to_simd(op)?; |
| 823 | + |
| 824 | + assert!(dest.layout.ty.is_integral()); |
| 825 | + assert_eq!(op_len.max(8), dest.layout.size.bits()); |
| 826 | + assert!(op_len <= 64); |
| 827 | + |
| 828 | + let mut res = 0u64; |
| 829 | + for i in 0..op_len { |
| 830 | + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; |
| 831 | + if simd_element_to_bool(op)? { |
| 832 | + res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); |
| 833 | + } |
| 834 | + } |
| 835 | + this.write_int(res, dest)?; |
| 836 | + } |
790 | 837 |
|
791 | 838 | // Atomic operations
|
792 | 839 | "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?,
|
@@ -1307,3 +1354,26 @@ fn fmin_op<'tcx>(
|
1307 | 1354 | FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)),
|
1308 | 1355 | })
|
1309 | 1356 | }
|
| 1357 | + |
| 1358 | +fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Tag> { |
| 1359 | + // SIMD uses all-1 as pattern for "true" |
| 1360 | + let val = if b { -1 } else { 0 }; |
| 1361 | + Scalar::from_int(val, size) |
| 1362 | +} |
| 1363 | + |
| 1364 | +fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { |
| 1365 | + let val = elem.to_scalar()?.to_int(elem.layout.size)?; |
| 1366 | + Ok(match val { |
| 1367 | + 0 => false, |
| 1368 | + -1 => true, |
| 1369 | + _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), |
| 1370 | + }) |
| 1371 | +} |
| 1372 | + |
| 1373 | +fn simd_bitmask_index(idx: u64, len: u64, endianess: Endian) -> u64 { |
| 1374 | + assert!(idx < len); |
| 1375 | + match endianess { |
| 1376 | + Endian::Little => idx, |
| 1377 | + Endian::Big => len.max(8) - 1 - idx, // reverse order of bits |
| 1378 | + } |
| 1379 | +} |
0 commit comments