about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduardo Sánchez Muñoz <eduardosm-dev@e64.io>2023-09-13 21:58:28 +0200
committerEduardo Sánchez Muñoz <eduardosm-dev@e64.io>2023-09-16 18:51:44 +0200
commit9fbbfd2e396a2d1c66168af9db80a806bcc5a32a (patch)
treedd45ff166b5591a0b2c4baf3d70b0755ed2d3f24
parent8d590f2fa84c0bb7bf423dfc3ea64b229e2f7346 (diff)
downloadrust-9fbbfd2e396a2d1c66168af9db80a806bcc5a32a.tar.gz
rust-9fbbfd2e396a2d1c66168af9db80a806bcc5a32a.zip
miri: reduce code duplication in SSE2 pmulh.w and pmulhu.w
Not really a saving in terms of lines of code, but at least the logic is de-duplicated
-rw-r--r--src/tools/miri/src/shims/x86/sse2.rs54
1 files changed, 27 insertions, 27 deletions
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index 28aebc8cba8..b68690a835c 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -88,8 +88,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     this.write_immediate(res, &dest)?;
                 }
             }
-            // Used to implement the _mm_mulhi_epi16 function.
-            "pmulh.w" => {
+            // Used to implement the _mm_mulhi_epi16 and _mm_mulhi_epu16 functions.
+            "pmulh.w" | "pmulhu.w" => {
                 let [left, right] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
 
@@ -101,35 +101,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 assert_eq!(dest_len, right_len);
 
                 for i in 0..dest_len {
-                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?;
-                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?;
+                    let left = this.read_immediate(&this.project_index(&left, i)?)?;
+                    let right = this.read_immediate(&this.project_index(&right, i)?)?;
                     let dest = this.project_index(&dest, i)?;
 
-                    // Values are expanded from i16 to i32, so multiplication cannot overflow.
-                    let res = i32::from(left).checked_mul(i32::from(right)).unwrap() >> 16;
-                    this.write_scalar(Scalar::from_i16(res.try_into().unwrap()), &dest)?;
-                }
-            }
-            // Used to implement the _mm_mulhi_epu16 function.
-            "pmulhu.w" => {
-                let [left, right] =
-                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-
-                let (left, left_len) = this.operand_to_simd(left)?;
-                let (right, right_len) = this.operand_to_simd(right)?;
-                let (dest, dest_len) = this.place_to_simd(dest)?;
-
-                assert_eq!(dest_len, left_len);
-                assert_eq!(dest_len, right_len);
+                    // Widen the operands to avoid overflow
+                    let twice_wide_ty = this.get_twice_wide_int_ty(left.layout.ty);
+                    let twice_wide_layout = this.layout_of(twice_wide_ty)?;
+                    let left = this.int_to_int_or_float(&left, twice_wide_ty)?;
+                    let right = this.int_to_int_or_float(&right, twice_wide_ty)?;
 
-                for i in 0..dest_len {
-                    let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u16()?;
-                    let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u16()?;
-                    let dest = this.project_index(&dest, i)?;
+                    // Multiply
+                    let (multiplied, _overflow, _ty) = this.overflowing_binary_op(
+                        mir::BinOp::Mul,
+                        &ImmTy::from_immediate(left, twice_wide_layout),
+                        &ImmTy::from_immediate(right, twice_wide_layout),
+                    )?;
+                    // Keep the high half
+                    let (high, _overflow, _ty) = this.overflowing_binary_op(
+                        mir::BinOp::Shr,
+                        &ImmTy::from_scalar(multiplied, twice_wide_layout),
+                        &ImmTy::from_uint(dest.layout.size.bits(), twice_wide_layout),
+                    )?;
 
-                    // Values are expanded from u16 to u32, so multiplication cannot overflow.
-                    let res = u32::from(left).checked_mul(u32::from(right)).unwrap() >> 16;
-                    this.write_scalar(Scalar::from_u16(res.try_into().unwrap()), &dest)?;
+                    // Narrow back to the original type
+                    let res = this.int_to_int_or_float(
+                        &ImmTy::from_scalar(high, twice_wide_layout),
+                        dest.layout.ty,
+                    )?;
+                    this.write_immediate(res, &dest)?;
                 }
             }
             // Used to implement the _mm_mul_epu32 function.