aboutsummaryrefslogtreecommitdiff
path: root/tcg
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2022-03-10 23:38:47 -0800
committerRichard Henderson <richard.henderson@linaro.org>2022-03-14 10:31:51 -0700
commit76cff100beeae8d3676bb658cccd45ef5ced8aa9 (patch)
treec1988135ad8645ebba6cde349647d13cb5c8d312 /tcg
parent6e591a8569b24309f0b602042cce630524c03c0e (diff)
tcg/arm: Don't emit UNPREDICTABLE LDRD with Rm == Rt or Rt+1
The LDRD (register) instruction is UNPREDICTABLE if the Rm register is the same as either Rt or Rt+1 (the two registers being loaded to). We weren't making sure we avoided this, with the result that on some host CPUs like the Cortex-A7 we would get a SIGILL because the CPU chooses to UNDEF for this particular UNPREDICTABLE case. Since we've already checked that datalo is aligned, we can simplify the test vs the Rm operand by aligning it before comparison. Check for the two orderings before falling back to two ldr instructions. We don't bother to do anything similar for tcg_out_ldrd_rwb(), because it is only used in tcg_out_tlb_read() with a fixed set of registers which don't overlap. There is no equivalent UNPREDICTABLE case for STRD. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/896 Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'tcg')
-rw-r--r--tcg/arm/tcg-target.c.inc17
1 files changed, 15 insertions, 2 deletions
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
index e1ea69669c..4bc0420f4d 100644
--- a/tcg/arm/tcg-target.c.inc
+++ b/tcg/arm/tcg-target.c.inc
@@ -1689,8 +1689,21 @@ static void tcg_out_qemu_ld_index(TCGContext *s, MemOp opc,
/* LDRD requires alignment; double-check that. */
if (get_alignment_bits(opc) >= MO_64
&& (datalo & 1) == 0 && datahi == datalo + 1) {
- tcg_out_ldrd_r(s, COND_AL, datalo, addrlo, addend);
- } else if (scratch_addend) {
+ /*
+ * Rm (the second address op) must not overlap Rt or Rt + 1.
+ * Since datalo is aligned, we can simplify the test via alignment.
+ * Flip the two address arguments if that works.
+ */
+ if ((addend & ~1) != datalo) {
+ tcg_out_ldrd_r(s, COND_AL, datalo, addrlo, addend);
+ break;
+ }
+ if ((addrlo & ~1) != datalo) {
+ tcg_out_ldrd_r(s, COND_AL, datalo, addend, addrlo);
+ break;
+ }
+ }
+ if (scratch_addend) {
tcg_out_ld32_rwb(s, COND_AL, datalo, addend, addrlo);
tcg_out_ld32_12(s, COND_AL, datahi, addend, 4);
} else {