[PATCH for-6.2 06/34] target/arm: Fix 48-bit saturating shifts

Peter Maydell posted 34 patches 4 years, 7 months ago
Maintainers: Peter Maydell <peter.maydell@linaro.org>
[PATCH for-6.2 06/34] target/arm: Fix 48-bit saturating shifts
Posted by Peter Maydell 4 years, 7 months ago
In do_sqrshl48_d() and do_uqrshl48_d() we got some of the edge
cases wrong and failed to saturate correctly:

(1) In do_sqrshl48_d() we used the same code that do_shrshl_bhs()
does to obtain the saturated most-negative and most-positive 48-bit
signed values for the large-shift-left case.  This gives (1 << 47)
for saturate-to-most-negative, but we weren't sign-extending this
value to the 64-bit output as the pseudocode requires.

(2) For left shifts by less than 48, we copied the "8/16 bit" code
from do_sqrshl_bhs() and do_uqrshl_bhs().  This doesn't do the right
thing because it assumes the C type we're working with is at least
twice the number of bits we're saturating to (so that a shift left by
bits-1 can't shift anything off the top of the value).  This isn't
true for bits == 48, so we would incorrectly return 0 rather than the
most-positive value for situations like "shift (1 << 44) right by
20".  Instead check for saturation by doing the shift and signextend
and then testing whether shifting back left again gives the original
value.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/mve_helper.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/target/arm/mve_helper.c b/target/arm/mve_helper.c
index 8cbfd3a8c53..f17e5a413fd 100644
--- a/target/arm/mve_helper.c
+++ b/target/arm/mve_helper.c
@@ -1579,9 +1579,8 @@ static inline int64_t do_sqrshl48_d(int64_t src, int64_t shift,
         }
         return src >> -shift;
     } else if (shift < 48) {
-        int64_t val = src << shift;
-        int64_t extval = sextract64(val, 0, 48);
-        if (!sat || val == extval) {
+        int64_t extval = sextract64(src << shift, 0, 48);
+        if (!sat || src == (extval >> shift)) {
             return extval;
         }
     } else if (!sat || src == 0) {
@@ -1589,7 +1588,7 @@ static inline int64_t do_sqrshl48_d(int64_t src, int64_t shift,
     }
 
     *sat = 1;
-    return (1ULL << 47) - (src >= 0);
+    return sextract64((1ULL << 47) - (src >= 0), 0, 48);
 }
 
 /* Operate on 64-bit values, but saturate at 48 bits */
@@ -1612,9 +1611,8 @@ static inline uint64_t do_uqrshl48_d(uint64_t src, int64_t shift,
             return extval;
         }
     } else if (shift < 48) {
-        uint64_t val = src << shift;
-        uint64_t extval = extract64(val, 0, 48);
-        if (!sat || val == extval) {
+        uint64_t extval = extract64(src << shift, 0, 48);
+        if (!sat || src == (extval >> shift)) {
             return extval;
         }
     } else if (!sat || src == 0) {
-- 
2.20.1


Re: [PATCH for-6.2 06/34] target/arm: Fix 48-bit saturating shifts
Posted by Richard Henderson 4 years, 6 months ago
On 7/13/21 6:36 AM, Peter Maydell wrote:
> -    return (1ULL << 47) - (src >= 0);
> +    return sextract64((1ULL << 47) - (src >= 0), 0, 48);

Clearer as

   return src >= 0 ? MAKE_64BIT_MASK(0, 47) : MAKE_64BIT_MASK(47, 17);

?  Otherwise,

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~

Re: [PATCH for-6.2 06/34] target/arm: Fix 48-bit saturating shifts
Posted by Peter Maydell 4 years, 6 months ago
On Fri, 16 Jul 2021 at 17:34, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 7/13/21 6:36 AM, Peter Maydell wrote:
> > -    return (1ULL << 47) - (src >= 0);
> > +    return sextract64((1ULL << 47) - (src >= 0), 0, 48);
>
> Clearer as
>
>    return src >= 0 ? MAKE_64BIT_MASK(0, 47) : MAKE_64BIT_MASK(47, 17);

Yeah, agreed.

thanks
-- PMM