Since 36a9529e60e0 the TCGv returned by compute_ldst_addr_type{a,b} for
the address can be a target register or a constant. However
do_{load,store} might modify it in the case of a reversed load/store.
Fix this by factoring out the reversed access logic and copying the
address in a new TCGv_i32 if it needs to be modified.
Fixes: 36a9529e60e0 (target/microblaze: Simplify compute_ldst_addr_type{a,b})
Signed-off-by: Luc Michel <luc.michel@amd.com>
---
target/microblaze/translate.c | 56 ++++++++++++++++++++---------------
1 file changed, 32 insertions(+), 24 deletions(-)
diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c
index 8b219afb5dd..9fb84e1bf9f 100644
--- a/target/microblaze/translate.c
+++ b/target/microblaze/translate.c
@@ -701,30 +701,47 @@ static void gen_alignment_check_ea(DisasContext *dc, TCGv_i64 ea, int rb,
static inline MemOp mo_endian(DisasContext *dc)
{
return dc->cfg->endi ? MO_LE : MO_BE;
}
+static void handle_reversed_access(MemOp *mop, TCGv_i32 *addr)
+{
+ MemOp size = *mop & MO_SIZE;
+
+ /*
+ * When doing reverse accesses we need to do two things.
+ *
+ * 1. Reverse the address wrt endianness.
+ * 2. Byteswap the data lanes on the way back into the CPU core.
+ *
+ * Use a new TCGv_i32 to modify the address because the current one might be
+ * a register or a constant.
+ */
+
+ if (size > MO_8) {
+ *mop ^= MO_BSWAP;
+ }
+
+ if (size < MO_32) {
+ TCGv_i32 new_addr = tcg_temp_new_i32();
+
+ tcg_gen_xori_i32(new_addr, *addr, 3 - size);
+ *addr = new_addr;
+ }
+}
+
static bool do_load(DisasContext *dc, int rd, TCGv_i32 addr, MemOp mop,
int mem_index, bool rev)
{
+#ifndef CONFIG_USER_ONLY
MemOp size = mop & MO_SIZE;
+#endif
mop |= mo_endian(dc);
- /*
- * When doing reverse accesses we need to do two things.
- *
- * 1. Reverse the address wrt endianness.
- * 2. Byteswap the data lanes on the way back into the CPU core.
- */
if (rev) {
- if (size > MO_8) {
- mop ^= MO_BSWAP;
- }
- if (size < MO_32) {
- tcg_gen_xori_i32(addr, addr, 3 - size);
- }
+ handle_reversed_access(&mop, &addr);
}
/*
* For system mode, enforce alignment if the cpu configuration
* requires it. For user-mode, the Linux kernel will have fixed up
@@ -864,27 +881,18 @@ static bool trans_lwx(DisasContext *dc, arg_typea *arg)
}
static bool do_store(DisasContext *dc, int rd, TCGv_i32 addr, MemOp mop,
int mem_index, bool rev)
{
+#ifndef CONFIG_USER_ONLY
MemOp size = mop & MO_SIZE;
+#endif
mop |= mo_endian(dc);
- /*
- * When doing reverse accesses we need to do two things.
- *
- * 1. Reverse the address wrt endianness.
- * 2. Byteswap the data lanes on the way back into the CPU core.
- */
if (rev) {
- if (size > MO_8) {
- mop ^= MO_BSWAP;
- }
- if (size < MO_32) {
- tcg_gen_xori_i32(addr, addr, 3 - size);
- }
+ handle_reversed_access(&mop, &addr);
}
/*
* For system mode, enforce alignment if the cpu configuration
* requires it. For user-mode, the Linux kernel will have fixed up
--
2.53.0