-
Notifications
You must be signed in to change notification settings - Fork 13.9k
Implement SIMD funnel shifts in const-eval/Miri #147534
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,7 +3,7 @@ use rustc_abi::Endian; | |||||||||
| use rustc_apfloat::ieee::{Double, Half, Quad, Single}; | ||||||||||
| use rustc_apfloat::{Float, Round}; | ||||||||||
| use rustc_middle::mir::interpret::{InterpErrorKind, UndefinedBehaviorInfo}; | ||||||||||
| use rustc_middle::ty::FloatTy; | ||||||||||
| use rustc_middle::ty::{FloatTy, ScalarInt}; | ||||||||||
| use rustc_middle::{bug, err_ub_format, mir, span_bug, throw_unsup_format, ty}; | ||||||||||
| use rustc_span::{Symbol, sym}; | ||||||||||
| use tracing::trace; | ||||||||||
|
|
@@ -724,6 +724,49 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { | |||||||||
| self.write_scalar(val, &dest)?; | ||||||||||
| } | ||||||||||
| } | ||||||||||
| sym::simd_funnel_shl | sym::simd_funnel_shr => { | ||||||||||
| let (left, _) = self.project_to_simd(&args[0])?; | ||||||||||
| let (right, _) = self.project_to_simd(&args[1])?; | ||||||||||
| let (shift, _) = self.project_to_simd(&args[2])?; | ||||||||||
| let (dest, _) = self.project_to_simd(&dest)?; | ||||||||||
|
|
||||||||||
| let (len, elem_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx); | ||||||||||
| let (elem_size, _signed) = elem_ty.int_size_and_signed(*self.tcx); | ||||||||||
| let elem_size_bits = u128::from(elem_size.bits()); | ||||||||||
|
|
||||||||||
| let is_left = intrinsic_name == sym::simd_funnel_shl; | ||||||||||
|
|
||||||||||
| for i in 0..len { | ||||||||||
| let left = | ||||||||||
| self.read_scalar(&self.project_index(&left, i)?)?.to_bits(elem_size)?; | ||||||||||
| let right = | ||||||||||
| self.read_scalar(&self.project_index(&right, i)?)?.to_bits(elem_size)?; | ||||||||||
| let shift_bits = | ||||||||||
| self.read_scalar(&self.project_index(&shift, i)?)?.to_bits(elem_size)?; | ||||||||||
|
|
||||||||||
| if shift_bits >= elem_size_bits { | ||||||||||
| throw_ub_format!( | ||||||||||
| "overflowing shift by {shift_bits} in `{intrinsic_name}` in lane {i}" | ||||||||||
| ); | ||||||||||
| } | ||||||||||
| let inv_shift_bits = u32::try_from(elem_size_bits - shift_bits).unwrap(); | ||||||||||
|
|
||||||||||
| // As `left` and `right` both occupy the lower `elem_size` bits, so we can treat | ||||||||||
| // the lower `elem_size` bits as an integer of that width. So the implementation | ||||||||||
| // of funnel shifts become easy. | ||||||||||
|
Comment on lines
+755
to
+756
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| // Note that the `unbounded_sh{l,r}`s are needed only in case we are using this | ||||||||||
| // on `u128xN` | ||||||||||
|
Comment on lines
+757
to
+758
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| let result_bits = if is_left { | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs a comment explaining why this logic, executed on u128, correctly implements the semantics for all integer types. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i added a comment, could you check if its enough |
||||||||||
| (left << shift_bits) | right.unbounded_shr(inv_shift_bits) | ||||||||||
| } else { | ||||||||||
| left.unbounded_shl(inv_shift_bits) | (right >> shift_bits) | ||||||||||
| }; | ||||||||||
| let (result, _overflow) = ScalarInt::truncate_from_uint(result_bits, elem_size); | ||||||||||
|
|
||||||||||
| let dest = self.project_index(&dest, i)?; | ||||||||||
| self.write_scalar(result, &dest)?; | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Unsupported intrinsic: skip the return_to_block below. | ||||||||||
| _ => return interp_ok(false), | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| #![feature(core_intrinsics, portable_simd)] | ||
|
|
||
| use std::intrinsics::simd::simd_funnel_shl; | ||
| use std::simd::*; | ||
|
|
||
| fn main() { | ||
| unsafe { | ||
| let x = i32x2::from_array([1, 1]); | ||
| let y = i32x2::from_array([100, 0]); | ||
| simd_funnel_shl(x, x, y); //~ERROR: overflowing shift by 100 in `simd_funnel_shl` in lane 0 | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| error: Undefined Behavior: overflowing shift by 100 in `simd_funnel_shl` in lane 0 | ||
| --> tests/fail/intrinsics/simd-funnel_shl-too-far.rs:LL:CC | ||
| | | ||
| LL | simd_funnel_shl(x, x, y); | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | ||
| | | ||
| = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior | ||
| = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information | ||
|
|
||
| note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | ||
|
|
||
| error: aborting due to 1 previous error | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| #![feature(core_intrinsics, portable_simd)] | ||
|
|
||
| use std::intrinsics::simd::simd_funnel_shr; | ||
| use std::simd::*; | ||
|
|
||
| fn main() { | ||
| unsafe { | ||
| let x = i32x2::from_array([1, 1]); | ||
| let y = i32x2::from_array([20, 40]); | ||
| simd_funnel_shr(x, x, y); //~ERROR: overflowing shift by 40 in `simd_funnel_shr` in lane 1 | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| error: Undefined Behavior: overflowing shift by 40 in `simd_funnel_shr` in lane 1 | ||
| --> tests/fail/intrinsics/simd-funnel_shr-too-far.rs:LL:CC | ||
| | | ||
| LL | simd_funnel_shr(x, x, y); | ||
| | ^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | ||
| | | ||
| = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior | ||
| = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information | ||
|
|
||
| note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | ||
|
|
||
| error: aborting due to 1 previous error | ||
|
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.