diff mbox series

[1/5] target/mips: Replace GET_OFFSET() macro by get_offset() function

Message ID 20210818164321.2474534-2-f4bug@amsat.org
State New
Headers show
Series target/mips: Replace TARGET_WORDS_BIGENDIAN by cpu_is_bigendian() | expand

Commit Message

Philippe Mathieu-Daudé Aug. 18, 2021, 4:43 p.m. UTC
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(-)

Comments

Richard Henderson Aug. 18, 2021, 4:56 p.m. UTC | #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~
Philippe Mathieu-Daudé Aug. 18, 2021, 9:31 p.m. UTC | #2
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 ;)
Richard Henderson Aug. 18, 2021, 10:29 p.m. UTC | #3
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~
diff mbox series

Patch

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());
     }
 }