Skip to content

Commit b3afd22

Browse files
committed
implement SIMD funnel shifts in const-eval
1 parent 1f880d9 commit b3afd22

File tree

5 files changed

+94
-1
lines changed

5 files changed

+94
-1
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_abi::Endian;
33
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
44
use rustc_apfloat::{Float, Round};
55
use rustc_middle::mir::interpret::{InterpErrorKind, UndefinedBehaviorInfo};
6-
use rustc_middle::ty::FloatTy;
6+
use rustc_middle::ty::{FloatTy, ScalarInt};
77
use rustc_middle::{bug, err_ub_format, mir, span_bug, throw_unsup_format, ty};
88
use rustc_span::{Symbol, sym};
99
use tracing::trace;
@@ -724,6 +724,49 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
724724
self.write_scalar(val, &dest)?;
725725
}
726726
}
727+
sym::simd_funnel_shl | sym::simd_funnel_shr => {
728+
let (left, _) = self.project_to_simd(&args[0])?;
729+
let (right, _) = self.project_to_simd(&args[1])?;
730+
let (shift, _) = self.project_to_simd(&args[2])?;
731+
let (dest, _) = self.project_to_simd(&dest)?;
732+
733+
let (len, elem_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx);
734+
let (elem_size, _signed) = elem_ty.int_size_and_signed(*self.tcx);
735+
let elem_size_bits = u128::from(elem_size.bits());
736+
737+
let is_left = intrinsic_name == sym::simd_funnel_shl;
738+
739+
for i in 0..len {
740+
let left =
741+
self.read_scalar(&self.project_index(&left, i)?)?.to_bits(elem_size)?;
742+
let right =
743+
self.read_scalar(&self.project_index(&right, i)?)?.to_bits(elem_size)?;
744+
let shift_bits =
745+
self.read_scalar(&self.project_index(&shift, i)?)?.to_bits(elem_size)?;
746+
747+
if shift_bits >= elem_size_bits {
748+
throw_ub_format!(
749+
"overflowing shift by {shift_bits} in `{intrinsic_name}` in lane {i}"
750+
);
751+
}
752+
let inv_shift_bits = u32::try_from(elem_size_bits - shift_bits).unwrap();
753+
754+
// As `left` and `right` both occupy the lower `elem_size` bits, so we can treat
755+
// the lower `elem_size` bits as an integer of that width. So the implementation
756+
// of funnel shifts become easy.
757+
// Note that the `unbounded_sh{l,r}`s are needed only in case we are using this
758+
// on `u128xN`
759+
let result_bits = if is_left {
760+
(left << shift_bits) | right.unbounded_shr(inv_shift_bits)
761+
} else {
762+
left.unbounded_shl(inv_shift_bits) | (right >> shift_bits)
763+
};
764+
let (result, _overflow) = ScalarInt::truncate_from_uint(result_bits, elem_size);
765+
766+
let dest = self.project_index(&dest, i)?;
767+
self.write_scalar(result, &dest)?;
768+
}
769+
}
727770

728771
// Unsupported intrinsic: skip the return_to_block below.
729772
_ => return interp_ok(false),
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![feature(core_intrinsics, portable_simd)]
2+
3+
use std::intrinsics::simd::simd_funnel_shl;
4+
use std::simd::*;
5+
6+
fn main() {
7+
unsafe {
8+
let x = i32x2::from_array([1, 1]);
9+
let y = i32x2::from_array([100, 0]);
10+
simd_funnel_shl(x, x, y); //~ERROR: overflowing shift by 100 in `simd_funnel_shl` in lane 0
11+
}
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: Undefined Behavior: overflowing shift by 100 in `simd_funnel_shl` in lane 0
2+
--> tests/fail/intrinsics/simd-funnel_shl-too-far.rs:LL:CC
3+
|
4+
LL | simd_funnel_shl(x, x, y);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
10+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
11+
12+
error: aborting due to 1 previous error
13+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![feature(core_intrinsics, portable_simd)]
2+
3+
use std::intrinsics::simd::simd_funnel_shr;
4+
use std::simd::*;
5+
6+
fn main() {
7+
unsafe {
8+
let x = i32x2::from_array([1, 1]);
9+
let y = i32x2::from_array([20, 40]);
10+
simd_funnel_shr(x, x, y); //~ERROR: overflowing shift by 40 in `simd_funnel_shr` in lane 1
11+
}
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: Undefined Behavior: overflowing shift by 40 in `simd_funnel_shr` in lane 1
2+
--> tests/fail/intrinsics/simd-funnel_shr-too-far.rs:LL:CC
3+
|
4+
LL | simd_funnel_shr(x, x, y);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
10+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
11+
12+
error: aborting due to 1 previous error
13+

0 commit comments

Comments
 (0)