diff mbox series

[1/7] target/ppc: introduce get_dfp{64,128}() helper functions

Message ID 20190924153556.27575-2-mark.cave-ayland@ilande.co.uk
State New
Headers show
Series target/ppc: DFP fixes and improvements | expand

Commit Message

Mark Cave-Ayland Sept. 24, 2019, 3:35 p.m. UTC
The existing functions (now incorrectly) assume that the MSB and LSB of DFP
numbers are stored as consecutive 64-bit words in memory. Instead of accessing
the DFP numbers directly, introduce get_dfp{64,128}() helper functions to ease
the switch to the correct representation.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 target/ppc/dfp_helper.c | 52 ++++++++++++++++++++++++++++++-----------
 1 file changed, 39 insertions(+), 13 deletions(-)

Comments

Richard Henderson Sept. 24, 2019, 7:21 p.m. UTC | #1
On 9/24/19 8:35 AM, Mark Cave-Ayland wrote:
> +static void get_dfp64(uint64_t *dst, uint64_t *dfp)
> +{
> +    dst[0] = dfp[0];
> +}
> +
> +static void get_dfp128(uint64_t *dst, uint64_t *dfp)
> +{
> +    dst[0] = dfp[HI_IDX];
> +    dst[1] = dfp[LO_IDX];
> +}

I'm not keen on this.  I would prefer some type difference that prevents you
from getting the arguments the wrong way around.

I'm thinking that a combination helper like

static void get_dfp64(decNumber *out, uint64_t *in)
{
    union {
       uint64_t i;
       decimal64 d;
    } u;

    u.i = *in;
    decimal64ToNumber(&u.d, out);
}

> @@ -129,7 +140,7 @@ static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a,
>      dfp->env = env;
>  
>      if (a) {
> -        dfp->a64[0] = *a;
> +        get_dfp64(dfp->a64, a);
>          decimal64ToNumber((decimal64 *)dfp->a64, &dfp->a);
>      } else {
>          dfp->a64[0] = 0;

becomes

    get_dfp64(&dfp->a, a);

and that might clean up a lot of the code.

> @@ -617,10 +626,12 @@ uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b)         \
>  {                                                                        \
>      struct PPC_DFP dfp;                                                  \
>      unsigned k;                                                          \
> +    uint64_t a64;                                                        \
>                                                                           \
>      dfp_prepare_decimal##size(&dfp, 0, b, env);                          \
>                                                                           \
> -    k = *a & 0x3F;                                                       \
> +    get_dfp64(&a64, a);                                                  \
> +    k = a64 & 0x3F;                                                      \
>                                                                           \
>      if (unlikely(decNumberIsSpecial(&dfp.b))) {                          \
>          dfp.crbf = 1;                                                    \

Whereas cases like this, where a scalar is being passed in, I don't think that
re-using the same helper is appropriate.  Ideally, they would be passed in by
value, and not by reference at all.  That, of course, requires changes to the
translator beyond the scope of this patch.

>  void helper_dctqpq(CPUPPCState *env, uint64_t *t, uint64_t *b)
>  {
>      struct PPC_DFP dfp;
> +    uint64_t b64;
>      dfp_prepare_decimal128(&dfp, 0, 0, env);
> -    decimal64ToNumber((decimal64 *)b, &dfp.t);
> +    get_dfp64(&b64, b);
> +    decimal64ToNumber((decimal64 *)&b64, &dfp.t);

This would become

    get_dfp64(&dfp.t, b);

with no intermediate b64 temp.


r~
Mark Cave-Ayland Sept. 24, 2019, 9:05 p.m. UTC | #2
On 24/09/2019 20:21, Richard Henderson wrote:

> On 9/24/19 8:35 AM, Mark Cave-Ayland wrote:
>> +static void get_dfp64(uint64_t *dst, uint64_t *dfp)
>> +{
>> +    dst[0] = dfp[0];
>> +}
>> +
>> +static void get_dfp128(uint64_t *dst, uint64_t *dfp)
>> +{
>> +    dst[0] = dfp[HI_IDX];
>> +    dst[1] = dfp[LO_IDX];
>> +}
> 
> I'm not keen on this.  I would prefer some type difference that prevents you
> from getting the arguments the wrong way around.
> 
> I'm thinking that a combination helper like
> 
> static void get_dfp64(decNumber *out, uint64_t *in)
> {
>     union {
>        uint64_t i;
>        decimal64 d;
>     } u;
> 
>     u.i = *in;
>     decimal64ToNumber(&u.d, out);
> }
> 
>> @@ -129,7 +140,7 @@ static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a,
>>      dfp->env = env;
>>  
>>      if (a) {
>> -        dfp->a64[0] = *a;
>> +        get_dfp64(dfp->a64, a);
>>          decimal64ToNumber((decimal64 *)dfp->a64, &dfp->a);
>>      } else {
>>          dfp->a64[0] = 0;
> 
> becomes
> 
>     get_dfp64(&dfp->a, a);
> 
> and that might clean up a lot of the code.

Right, and in fact I had a similar thought myself regarding type safety since one of
the issues with working with the existing code in dfp_helper.c is that everything
uses a uint64_t * which makes it really difficult to figure out why things are
crashing if you make a typo :/

Note that this patch simply introduces the helpers without making changes to the
existing logic which is why both arguments are still uint64_t *. The real work is
done in patch 3 where ppc_fptr_t type is introduced, and also see the switch from
uint64_t * to ppc_vsr_t in patch 5.

With the full patchset applied you'll see that get_dfp64() and friends are in exactly
the same form you show above, and if I swap the arguments then the compiler does
actually complain, although somewhat cryptically.

>> @@ -617,10 +626,12 @@ uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b)         \
>>  {                                                                        \
>>      struct PPC_DFP dfp;                                                  \
>>      unsigned k;                                                          \
>> +    uint64_t a64;                                                        \
>>                                                                           \
>>      dfp_prepare_decimal##size(&dfp, 0, b, env);                          \
>>                                                                           \
>> -    k = *a & 0x3F;                                                       \
>> +    get_dfp64(&a64, a);                                                  \
>> +    k = a64 & 0x3F;                                                      \
>>                                                                           \
>>      if (unlikely(decNumberIsSpecial(&dfp.b))) {                          \
>>          dfp.crbf = 1;                                                    \
> 
> Whereas cases like this, where a scalar is being passed in, I don't think that
> re-using the same helper is appropriate.  Ideally, they would be passed in by
> value, and not by reference at all.  That, of course, requires changes to the
> translator beyond the scope of this patch.

Agreed. I was really keen to avoid any translator changes if possible since the PPC
translator code tends to be quite tricky which is why I went with the above approach.

>>  void helper_dctqpq(CPUPPCState *env, uint64_t *t, uint64_t *b)
>>  {
>>      struct PPC_DFP dfp;
>> +    uint64_t b64;
>>      dfp_prepare_decimal128(&dfp, 0, 0, env);
>> -    decimal64ToNumber((decimal64 *)b, &dfp.t);
>> +    get_dfp64(&b64, b);
>> +    decimal64ToNumber((decimal64 *)&b64, &dfp.t);
> 
> This would become
> 
>     get_dfp64(&dfp.t, b);
> 
> with no intermediate b64 temp.

Funnily enough that did cross my mind, but I wasn't 100% sure that this wasn't doing
something extra within libdecnumber. If you think it makes sense then I can easily
add it into a v2.


ATB,

Mark.
Richard Henderson Sept. 24, 2019, 9:29 p.m. UTC | #3
On 9/24/19 2:05 PM, Mark Cave-Ayland wrote:
> With the full patchset applied you'll see that get_dfp64() and friends are
> in exactly the same form you show above, and if I swap the arguments then
> the compiler does actually complain, although somewhat cryptically.
Oh, good.  I'll finish reading the whole set before making too many more
comments ahead of your actual steps.


r~
diff mbox series

Patch

diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c
index f102177572..354a4aa877 100644
--- a/target/ppc/dfp_helper.c
+++ b/target/ppc/dfp_helper.c
@@ -36,6 +36,17 @@ 
 #define LO_IDX 0
 #endif
 
+static void get_dfp64(uint64_t *dst, uint64_t *dfp)
+{
+    dst[0] = dfp[0];
+}
+
+static void get_dfp128(uint64_t *dst, uint64_t *dfp)
+{
+    dst[0] = dfp[HI_IDX];
+    dst[1] = dfp[LO_IDX];
+}
+
 struct PPC_DFP {
     CPUPPCState *env;
     uint64_t t64[2], a64[2], b64[2];
@@ -129,7 +140,7 @@  static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a,
     dfp->env = env;
 
     if (a) {
-        dfp->a64[0] = *a;
+        get_dfp64(dfp->a64, a);
         decimal64ToNumber((decimal64 *)dfp->a64, &dfp->a);
     } else {
         dfp->a64[0] = 0;
@@ -137,7 +148,7 @@  static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a,
     }
 
     if (b) {
-        dfp->b64[0] = *b;
+        get_dfp64(dfp->b64, b);
         decimal64ToNumber((decimal64 *)dfp->b64, &dfp->b);
     } else {
         dfp->b64[0] = 0;
@@ -153,8 +164,7 @@  static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a,
     dfp->env = env;
 
     if (a) {
-        dfp->a64[0] = a[HI_IDX];
-        dfp->a64[1] = a[LO_IDX];
+        get_dfp128(dfp->a64, a);
         decimal128ToNumber((decimal128 *)dfp->a64, &dfp->a);
     } else {
         dfp->a64[0] = dfp->a64[1] = 0;
@@ -162,8 +172,7 @@  static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a,
     }
 
     if (b) {
-        dfp->b64[0] = b[HI_IDX];
-        dfp->b64[1] = b[LO_IDX];
+        get_dfp128(dfp->b64, b);
         decimal128ToNumber((decimal128 *)dfp->b64, &dfp->b);
     } else {
         dfp->b64[0] = dfp->b64[1] = 0;
@@ -617,10 +626,12 @@  uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b)         \
 {                                                                        \
     struct PPC_DFP dfp;                                                  \
     unsigned k;                                                          \
+    uint64_t a64;                                                        \
                                                                          \
     dfp_prepare_decimal##size(&dfp, 0, b, env);                          \
                                                                          \
-    k = *a & 0x3F;                                                       \
+    get_dfp64(&a64, a);                                                  \
+    k = a64 & 0x3F;                                                      \
                                                                          \
     if (unlikely(decNumberIsSpecial(&dfp.b))) {                          \
         dfp.crbf = 1;                                                    \
@@ -817,11 +828,15 @@  void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a,            \
                  uint64_t *b, uint32_t rmc)                             \
 {                                                                       \
     struct PPC_DFP dfp;                                                 \
-    int32_t ref_sig = *a & 0x3F;                                        \
+    uint64_t a64;                                                       \
+    int32_t ref_sig;                                                    \
     int32_t xmax = ((size) == 64) ? 369 : 6111;                         \
                                                                         \
     dfp_prepare_decimal##size(&dfp, 0, b, env);                         \
                                                                         \
+    get_dfp64(&a64, a);                                                 \
+    ref_sig = a64 & 0x3f;                                               \
+                                                                        \
     _dfp_reround(rmc, ref_sig, xmax, &dfp);                             \
     decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t,         \
                               &dfp.context);                            \
@@ -881,7 +896,12 @@  DFP_HELPER_RINT(drintnq, RINTN_PPs, 128)
 void helper_dctdp(CPUPPCState *env, uint64_t *t, uint64_t *b)
 {
     struct PPC_DFP dfp;
-    uint32_t b_short = *b;
+    uint64_t b64;
+    uint32_t b_short;
+
+    get_dfp64(&b64, b);
+    b_short = (uint32_t)b64;
+
     dfp_prepare_decimal64(&dfp, 0, 0, env);
     decimal32ToNumber((decimal32 *)&b_short, &dfp.t);
     decimal64FromNumber((decimal64 *)t, &dfp.t, &dfp.context);
@@ -891,8 +911,10 @@  void helper_dctdp(CPUPPCState *env, uint64_t *t, uint64_t *b)
 void helper_dctqpq(CPUPPCState *env, uint64_t *t, uint64_t *b)
 {
     struct PPC_DFP dfp;
+    uint64_t b64;
     dfp_prepare_decimal128(&dfp, 0, 0, env);
-    decimal64ToNumber((decimal64 *)b, &dfp.t);
+    get_dfp64(&b64, b);
+    decimal64ToNumber((decimal64 *)&b64, &dfp.t);
 
     dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp);
     dfp_set_FPRF_from_FRT(&dfp);
@@ -940,8 +962,10 @@  void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b)
 void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b)                   \
 {                                                                              \
     struct PPC_DFP dfp;                                                        \
+    uint64_t b64;                                                              \
     dfp_prepare_decimal##size(&dfp, 0, b, env);                                \
-    decNumberFromInt64(&dfp.t, (int64_t)(*b));                                 \
+    get_dfp64(&b64, b);                                                        \
+    decNumberFromInt64(&dfp.t, (int64_t)b64);                                  \
     decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \
     CFFIX_PPs(&dfp);                                                           \
                                                                                \
@@ -1183,10 +1207,12 @@  static void dfp_set_raw_exp_128(uint64_t *t, uint64_t raw)
 void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \
 {                                                                         \
     struct PPC_DFP dfp;                                                   \
-    uint64_t raw_qnan, raw_snan, raw_inf, max_exp;                        \
+    uint64_t raw_qnan, raw_snan, raw_inf, max_exp, a64;                   \
     int bias;                                                             \
-    int64_t exp = *((int64_t *)a);                                        \
+    int64_t exp;                                                          \
                                                                           \
+    get_dfp64(&a64, a);                                                   \
+    exp = (int64_t)a64;                                                   \
     dfp_prepare_decimal##size(&dfp, 0, b, env);                           \
                                                                           \
     if ((size) == 64) {                                                   \