The target endianess information is stored in the BigEndian
bit of the Config0 register in CP0.
As a first step, replace the GET_OFFSET() macro by an inlined
get_offset() function, passing CPUMIPSState as argument.
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
target/mips/tcg/ldst_helper.c | 57 +++++++++++++++++++++--------------
1 file changed, 35 insertions(+), 22 deletions(-)
diff --git a/target/mips/tcg/ldst_helper.c b/target/mips/tcg/ldst_helper.c
index d42812b8a6a..97e7ad7d7a4 100644
--- a/target/mips/tcg/ldst_helper.c
+++ b/target/mips/tcg/ldst_helper.c
@@ -52,31 +52,44 @@ HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong))
#endif /* !CONFIG_USER_ONLY */
+static inline bool cpu_is_bigendian(CPUMIPSState *env)
+{
+ return extract32(env->CP0_Config0, CP0C0_BE, 1);
+}
+
#ifdef TARGET_WORDS_BIGENDIAN
#define GET_LMASK(v) ((v) & 3)
-#define GET_OFFSET(addr, offset) (addr + (offset))
#else
#define GET_LMASK(v) (((v) & 3) ^ 3)
-#define GET_OFFSET(addr, offset) (addr - (offset))
#endif
+static inline target_ulong get_offset(CPUMIPSState *env,
+ target_ulong addr, int offset)
+{
+ if (cpu_is_bigendian(env)) {
+ return addr + offset;
+ } else {
+ return addr - offset;
+ }
+}
+
void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
int mem_idx)
{
cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
if (GET_LMASK(arg2) <= 2) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 1), (uint8_t)(arg1 >> 16),
mem_idx, GETPC());
}
if (GET_LMASK(arg2) <= 1) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 2), (uint8_t)(arg1 >> 8),
mem_idx, GETPC());
}
if (GET_LMASK(arg2) == 0) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)arg1,
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 3), (uint8_t)arg1,
mem_idx, GETPC());
}
}
@@ -87,17 +100,17 @@ void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
if (GET_LMASK(arg2) >= 1) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, -1), (uint8_t)(arg1 >> 8),
mem_idx, GETPC());
}
if (GET_LMASK(arg2) >= 2) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, -2), (uint8_t)(arg1 >> 16),
mem_idx, GETPC());
}
if (GET_LMASK(arg2) == 3) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, -3), (uint8_t)(arg1 >> 24),
mem_idx, GETPC());
}
}
@@ -119,37 +132,37 @@ void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC());
if (GET_LMASK64(arg2) <= 6) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 1), (uint8_t)(arg1 >> 48),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) <= 5) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 2), (uint8_t)(arg1 >> 40),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) <= 4) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 3), (uint8_t)(arg1 >> 32),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) <= 3) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 4), (uint8_t)(arg1 >> 24),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) <= 2) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 5), (uint8_t)(arg1 >> 16),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) <= 1) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 6), (uint8_t)(arg1 >> 8),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) <= 0) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 7), (uint8_t)arg1,
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 7), (uint8_t)arg1,
mem_idx, GETPC());
}
}
@@ -160,37 +173,37 @@ void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
if (GET_LMASK64(arg2) >= 1) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, -1), (uint8_t)(arg1 >> 8),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) >= 2) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, -2), (uint8_t)(arg1 >> 16),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) >= 3) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, -3), (uint8_t)(arg1 >> 24),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) >= 4) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, -4), (uint8_t)(arg1 >> 32),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) >= 5) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, -5), (uint8_t)(arg1 >> 40),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) >= 6) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, -6), (uint8_t)(arg1 >> 48),
mem_idx, GETPC());
}
if (GET_LMASK64(arg2) == 7) {
- cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56),
+ cpu_stb_mmuidx_ra(env, get_offset(env, arg2, -7), (uint8_t)(arg1 >> 56),
mem_idx, GETPC());
}
}
--
2.31.1
On 8/18/21 6:43 AM, Philippe Mathieu-Daudé wrote:
> The target endianess information is stored in the BigEndian
> bit of the Config0 register in CP0.
>
> As a first step, replace the GET_OFFSET() macro by an inlined
> get_offset() function, passing CPUMIPSState as argument.
>
> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
> target/mips/tcg/ldst_helper.c | 57 +++++++++++++++++++++--------------
> 1 file changed, 35 insertions(+), 22 deletions(-)
>
> diff --git a/target/mips/tcg/ldst_helper.c b/target/mips/tcg/ldst_helper.c
> index d42812b8a6a..97e7ad7d7a4 100644
> --- a/target/mips/tcg/ldst_helper.c
> +++ b/target/mips/tcg/ldst_helper.c
> @@ -52,31 +52,44 @@ HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong))
>
> #endif /* !CONFIG_USER_ONLY */
>
> +static inline bool cpu_is_bigendian(CPUMIPSState *env)
> +{
> + return extract32(env->CP0_Config0, CP0C0_BE, 1);
> +}
> +
> #ifdef TARGET_WORDS_BIGENDIAN
> #define GET_LMASK(v) ((v) & 3)
> -#define GET_OFFSET(addr, offset) (addr + (offset))
> #else
> #define GET_LMASK(v) (((v) & 3) ^ 3)
> -#define GET_OFFSET(addr, offset) (addr - (offset))
> #endif
>
> +static inline target_ulong get_offset(CPUMIPSState *env,
> + target_ulong addr, int offset)
> +{
> + if (cpu_is_bigendian(env)) {
> + return addr + offset;
> + } else {
> + return addr - offset;
> + }
> +}
> +
> void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
> int mem_idx)
> {
> cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
>
> if (GET_LMASK(arg2) <= 2) {
> - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16),
> + cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 1), (uint8_t)(arg1 >> 16),
> mem_idx, GETPC());
> }
>
> if (GET_LMASK(arg2) <= 1) {
> - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8),
> + cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 2), (uint8_t)(arg1 >> 8),
> mem_idx, GETPC());
So... yes, this is an improvement, but it's now substituting a constant for a runtime
variable many times over. I think you should drop get_offset() entirely and replace it with
int dir = cpu_is_bigendian(env) ? 1 : -1;
stb(env, arg2 + 1 * dir, data);
stb(env, arg2 + 2 * dir, data);
Alternately, bite the bullet and split the function(s) into two, explicitly endian
versions: helper_swl_be, helper_swl_le, etc.
r~
On 8/18/21 6:56 PM, Richard Henderson wrote:
> On 8/18/21 6:43 AM, Philippe Mathieu-Daudé wrote:
>> The target endianess information is stored in the BigEndian
>> bit of the Config0 register in CP0.
>>
>> As a first step, replace the GET_OFFSET() macro by an inlined
>> get_offset() function, passing CPUMIPSState as argument.
>>
>> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
>> ---
>> target/mips/tcg/ldst_helper.c | 57 +++++++++++++++++++++--------------
>> 1 file changed, 35 insertions(+), 22 deletions(-)
>>
>> diff --git a/target/mips/tcg/ldst_helper.c
>> b/target/mips/tcg/ldst_helper.c
>> index d42812b8a6a..97e7ad7d7a4 100644
>> --- a/target/mips/tcg/ldst_helper.c
>> +++ b/target/mips/tcg/ldst_helper.c
>> @@ -52,31 +52,44 @@ HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong))
>> #endif /* !CONFIG_USER_ONLY */
>> +static inline bool cpu_is_bigendian(CPUMIPSState *env)
>> +{
>> + return extract32(env->CP0_Config0, CP0C0_BE, 1);
>> +}
>> +
>> #ifdef TARGET_WORDS_BIGENDIAN
>> #define GET_LMASK(v) ((v) & 3)
>> -#define GET_OFFSET(addr, offset) (addr + (offset))
>> #else
>> #define GET_LMASK(v) (((v) & 3) ^ 3)
>> -#define GET_OFFSET(addr, offset) (addr - (offset))
>> #endif
>> +static inline target_ulong get_offset(CPUMIPSState *env,
>> + target_ulong addr, int offset)
>> +{
>> + if (cpu_is_bigendian(env)) {
>> + return addr + offset;
>> + } else {
>> + return addr - offset;
>> + }
>> +}
>> +
>> void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong
>> arg2,
>> int mem_idx)
>> {
>> cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 24), mem_idx,
>> GETPC());
>> if (GET_LMASK(arg2) <= 2) {
>> - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >>
>> 16),
>> + cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 1),
>> (uint8_t)(arg1 >> 16),
>> mem_idx, GETPC());
>> }
>> if (GET_LMASK(arg2) <= 1) {
>> - cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >>
>> 8),
>> + cpu_stb_mmuidx_ra(env, get_offset(env, arg2, 2),
>> (uint8_t)(arg1 >> 8),
>> mem_idx, GETPC());
>
> So... yes, this is an improvement, but it's now substituting a constant
> for a runtime variable many times over.
Oops indeed.
> I think you should drop
> get_offset() entirely and replace it with
>
> int dir = cpu_is_bigendian(env) ? 1 : -1;
>
> stb(env, arg2 + 1 * dir, data);
>
> stb(env, arg2 + 2 * dir, data);
>
> Alternately, bite the bullet and split the function(s) into two,
> explicitly endian versions: helper_swl_be, helper_swl_le, etc.
I'll go for the easier path ;)
On 8/18/21 11:31 AM, Philippe Mathieu-Daudé wrote:
>> I think you should drop
>> get_offset() entirely and replace it with
>>
>> int dir = cpu_is_bigendian(env) ? 1 : -1;
>>
>> stb(env, arg2 + 1 * dir, data);
>>
>> stb(env, arg2 + 2 * dir, data);
>>
>> Alternately, bite the bullet and split the function(s) into two,
>> explicitly endian versions: helper_swl_be, helper_swl_le, etc.
>
> I'll go for the easier path ;)
It's not really more difficult.
static inline void do_swl(env, uint32_t val, target_ulong addr, int midx,
int dir, unsigned lmask, uintptr_t ra)
{
cpu_stb_mmuidx_ra(env, addr, val >> 24, midx, ra);
if (lmask <= 2) {
cpu_stb_mmuidx_ra(env, addr + 1 * dir, val >> 16, midx, ra);
}
if (lmask <= 1) {
cpu_stb_mmuidx_ra(env, addr + 1 * dir, val >> 8, midx, ra);
}
if (lmask == 0) {
cpu_stb_mmuidx_ra(env, addr + 1 * dir, val, midx, ra);
}
}
void helper_swl_be(env, val, addr, midx)
{
do_swl(env, val, addr, midx, 1, addr & 3, GETPC());
}
void helper_swl_le(env, val, addr, midx)
{
do_swl(env, val, addr, midx, -1, ~addr & 3, GETPC());
}
Although I do wonder if this is strictly correct with respect to atomicity. In my
tcg/mips unaligned patch set, I assumed that lwl+lwr of an aligned address produces two
atomic 32-bit loads, which result in a complete atomic load at the end.
Should we be doing something like
void helper_swl_be(env, val, addr, midx)
{
uintptr_t ra = GETPC();
switch (addr & 3) {
case 0:
cpu_stl_be_mmuidx_ra(env, val, addr, midx, ra);
break;
case 1:
cpu_stb_mmuidx_ra(env, val >> 24, addr, midx, ra);
cpu_stw_be_mmuidx_ra(env, val >> 16, addr + 1, midx, ra);
break;
case 2:
cpu_stw_be_mmuidx_ra(env, val >> 16, addr, midx, ra);
break;
case 3:
cpu_stb_mmuidx_ra(env, val >> 24, addr, midx, ra);
break;
}
}
void helper_swl_le(env, val, addr, midx)
{
uintptr_t ra = GETPC();
/*
* We want to use stw and stl for atomicity, but want any
* fault to report ADDR, not the aligned address.
*/
probe_write(env, addr, 0, midx, ra);
switch (addr & 3) {
case 3:
cpu_stl_le_mmuidx_ra(env, val, addr - 3, midx, ra);
break;
case 1:
cpu_stw_le_mmuidx_ra(env, val >> 16, addr - 1, midx, ra);
break;
case 2:
cpu_stw_le_mmuidx_ra(env, val >> 8, addr - 2, midx, ra);
/* fall through */
case 0:
cpu_stb_mmuidx_ra(env, val >> 24, addr, midx, ra);
break;
}
}
etc.
r~
© 2016 - 2026 Red Hat, Inc.