Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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 243705a)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
  • Loading branch information
pm215 authored and Michael Tokarev committed Jun 22, 2023
1 parent 23315ad commit 1bc596d
Showing 1 changed file with 16 additions and 2 deletions.
18 changes: 16 additions & 2 deletions target/arm/translate-a64.c
Expand Up @@ -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();
}
}
}

Expand Down

0 comments on commit 1bc596d

Please sign in to comment.