aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2023-06-19 11:20:18 +0100
committerMichael Tokarev <mjt@tls.msk.ru>2023-06-22 10:34:30 +0300
commit1bc596d079dba75794560e0b52f1b0cb7d5dd3a4 (patch)
tree4a37ac1ee6e356275194d4350cf01524542b58e5
parent23315ad0b8c04423fd274e9c571ae2cee9bd50c2 (diff)
downloadqemu-1bc596d079dba75794560e0b52f1b0cb7d5dd3a4.zip
qemu-1bc596d079dba75794560e0b52f1b0cb7d5dd3a4.tar.gz
qemu-1bc596d079dba75794560e0b52f1b0cb7d5dd3a4.tar.bz2
target/arm: Fix return value from LDSMIN/LDSMAX 8/16 bit atomics
The atomic memory operations are supposed to return the old memory data value in the destination register. This value is not sign-extended, even if the operation is the signed minimum or maximum. (In the pseudocode for the instructions the returned data value is passed to ZeroExtend() to create the value in the register.) We got this wrong because we were doing a 32-to-64 zero extend on the result for 8 and 16 bit data values, rather than the correct amount of zero extension. Fix the bug by using ext8u and ext16u for the MO_8 and MO_16 data sizes rather than ext32u. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20230602155223.2040685-2-peter.maydell@linaro.org (cherry picked from commit 243705aa6ea3465b20e9f5a8bfcf36d3153f3c10) Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
-rw-r--r--target/arm/translate-a64.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 2ee171f..3c356d2 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -3536,8 +3536,22 @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
*/
fn(tcg_rt, clean_addr, tcg_rs, get_mem_index(s), mop);
- if ((mop & MO_SIGN) && size != MO_64) {
- tcg_gen_ext32u_i64(tcg_rt, tcg_rt);
+ if (mop & MO_SIGN) {
+ switch (size) {
+ case MO_8:
+ tcg_gen_ext8u_i64(tcg_rt, tcg_rt);
+ break;
+ case MO_16:
+ tcg_gen_ext16u_i64(tcg_rt, tcg_rt);
+ break;
+ case MO_32:
+ tcg_gen_ext32u_i64(tcg_rt, tcg_rt);
+ break;
+ case MO_64:
+ break;
+ default:
+ g_assert_not_reached();
+ }
}
}