aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-08-13 17:11:48 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-08-25 10:48:48 +0100
commit95351aa76c8f68564c4be547c1d19d9cabffc147 (patch)
treeca8ad3cfcfd691c991c587a32da4b0a9c0846d29
parenta5e59e8dcbbf7b1205370b3f4519749df5d0b726 (diff)
downloadqemu-95351aa76c8f68564c4be547c1d19d9cabffc147.zip
qemu-95351aa76c8f68564c4be547c1d19d9cabffc147.tar.gz
qemu-95351aa76c8f68564c4be547c1d19d9cabffc147.tar.bz2
target/arm: Fix 48-bit saturating shifts
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> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r--target/arm/mve_helper.c12
1 files changed, 5 insertions, 7 deletions
diff --git a/target/arm/mve_helper.c b/target/arm/mve_helper.c
index 847ef51..5730b48 100644
--- a/target/arm/mve_helper.c
+++ b/target/arm/mve_helper.c
@@ -1576,9 +1576,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) {
@@ -1586,7 +1585,7 @@ static inline int64_t do_sqrshl48_d(int64_t src, int64_t shift,
}
*sat = 1;
- return (1ULL << 47) - (src >= 0);
+ return src >= 0 ? MAKE_64BIT_MASK(0, 47) : MAKE_64BIT_MASK(47, 17);
}
/* Operate on 64-bit values, but saturate at 48 bits */
@@ -1609,9 +1608,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) {