diff mbox

[v2,2/5] target-tricore: Added MADD.F and MSUB.F instructions

Message ID 20161107144445.14069-3-kbastian@mail.uni-paderborn.de
State New
Headers show

Commit Message

Bastian Koppelmann Nov. 7, 2016, 2:44 p.m. UTC
Multiplies D[a] and D[b] and adds/subtracts the result to/from D[d].
The result is put in D[c]. All operands are floating-point numbers.

Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
---
 target-tricore/fpu_helper.c | 93 ++++++++++++++++++++++++++++++++++++++++++++-
 target-tricore/helper.h     |  2 +
 target-tricore/translate.c  |  8 ++++
 3 files changed, 102 insertions(+), 1 deletion(-)

Comments

Richard Henderson Nov. 8, 2016, 11:42 a.m. UTC | #1
On 11/07/2016 03:44 PM, Bastian Koppelmann wrote:
> Multiplies D[a] and D[b] and adds/subtracts the result to/from D[d].
> The result is put in D[c]. All operands are floating-point numbers.
>
> Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
> ---
>  target-tricore/fpu_helper.c | 93 ++++++++++++++++++++++++++++++++++++++++++++-
>  target-tricore/helper.h     |  2 +
>  target-tricore/translate.c  |  8 ++++
>  3 files changed, 102 insertions(+), 1 deletion(-)
>
> diff --git a/target-tricore/fpu_helper.c b/target-tricore/fpu_helper.c
> index f717b53..d530a0b 100644
> --- a/target-tricore/fpu_helper.c
> +++ b/target-tricore/fpu_helper.c
> @@ -21,7 +21,8 @@
>  #include "cpu.h"
>  #include "exec/helper-proto.h"
>
> -#define ADD_NAN   0x7cf00001
> +#define QUIET_NAN 0x7fc00000
> +#define ADD_NAN   0x7fc00001
>  #define DIV_NAN   0x7fc00008
>  #define MUL_NAN   0x7fc00002
>  #define FPU_FS PSW_USB_C
> @@ -47,6 +48,42 @@ static inline bool f_is_denormal(float32 arg)
>      return float32_is_zero_or_denormal(arg) && !float32_is_zero(arg);
>  }
>
> +static inline float32 f_maddsub_nan_result(float32 arg1, float32 arg2,
> +                                           float32 arg3, float32 result,
> +                                           uint32_t flags)
> +{
> +    uint32_t aSign, bSign, cSign;
> +    uint32_t aExp, bExp, cExp;
> +
> +    if (float32_is_any_nan(arg1) || float32_is_any_nan(arg2) ||
> +        float32_is_any_nan(arg3)) {
> +        return QUIET_NAN;
> +    } else if (float32_is_infinity(arg1) && float32_is_zero(arg2)) {
> +        return MUL_NAN;
> +    } else if (float32_is_zero(arg1) && float32_is_infinity(arg2)) {
> +        return MUL_NAN;
> +    } else {
> +        aSign = arg1 >> 31;
> +        bSign = arg2 >> 31;
> +        cSign = arg3 >> 31;
> +
> +        aExp = (arg1 >> 23) & 0xff;
> +        bExp = (arg2 >> 23) & 0xff;
> +        cExp = (arg3 >> 23) & 0xff;
> +
> +        if (flags & float_muladd_negate_c) {

flags here is muladd argument,

> +    flags = f_get_excp_flags(env);
> +    if (flags) {
> +        if (flags & float_flag_invalid) {
> +            arg1 = float32_squash_input_denormal(arg1, &env->fp_status);
> +            arg2 = float32_squash_input_denormal(arg2, &env->fp_status);
> +            arg3 = float32_squash_input_denormal(arg3, &env->fp_status);
> +            f_result = f_maddsub_nan_result(arg1, arg2, arg3, f_result, flags);

but passed here as exception bits.

> +        }
> +        f_update_psw_flags(env, flags);
> +    } else {
> +        env->FPU_FS = 0;
> +    }
> +    return (uint32_t)f_result;
> +}
> +
> +uint32_t helper_fmsub(CPUTriCoreState *env, uint32_t r1,
> +                      uint32_t r2, uint32_t r3)
> +{
> +    uint32_t flags;
> +    float32 arg1 = make_float32(r1);
> +    float32 arg2 = make_float32(r2);
> +    float32 arg3 = make_float32(r3);
> +    float32 f_result;
> +
> +    f_result = float32_muladd(arg1, arg2, arg3, float_muladd_negate_product,
> +                              &env->fp_status);
> +
> +    flags = f_get_excp_flags(env);
> +    if (flags) {
> +        if (flags & float_flag_invalid) {
> +            arg1 = float32_squash_input_denormal(arg1, &env->fp_status);
> +            arg2 = float32_squash_input_denormal(arg2, &env->fp_status);
> +            arg3 = float32_squash_input_denormal(arg3, &env->fp_status);
> +
> +            f_result = f_maddsub_nan_result(arg1, arg2, arg3, f_result, flags);

Same.  Also, nan_result needs to check float_muladd_negate_product as used 
here, not float_muladd_negate_c as used above.


r~
Bastian Koppelmann Nov. 8, 2016, 3:08 p.m. UTC | #2
On 11/08/2016 12:42 PM, Richard Henderson wrote:
> On 11/07/2016 03:44 PM, Bastian Koppelmann wrote:
>> Multiplies D[a] and D[b] and adds/subtracts the result to/from D[d].
>> The result is put in D[c]. All operands are floating-point numbers.
>>
>> Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
>> ---
>>  target-tricore/fpu_helper.c | 93
>> ++++++++++++++++++++++++++++++++++++++++++++-
>>  target-tricore/helper.h     |  2 +
>>  target-tricore/translate.c  |  8 ++++
>>  3 files changed, 102 insertions(+), 1 deletion(-)
>>
>> diff --git a/target-tricore/fpu_helper.c b/target-tricore/fpu_helper.c
>> index f717b53..d530a0b 100644
>> --- a/target-tricore/fpu_helper.c
>> +++ b/target-tricore/fpu_helper.c
>> @@ -21,7 +21,8 @@
>>  #include "cpu.h"
>>  #include "exec/helper-proto.h"
>>
>> -#define ADD_NAN   0x7cf00001
>> +#define QUIET_NAN 0x7fc00000
>> +#define ADD_NAN   0x7fc00001
>>  #define DIV_NAN   0x7fc00008
>>  #define MUL_NAN   0x7fc00002
>>  #define FPU_FS PSW_USB_C
>> @@ -47,6 +48,42 @@ static inline bool f_is_denormal(float32 arg)
>>      return float32_is_zero_or_denormal(arg) && !float32_is_zero(arg);
>>  }
>>
>> +static inline float32 f_maddsub_nan_result(float32 arg1, float32 arg2,
>> +                                           float32 arg3, float32 result,
>> +                                           uint32_t flags)
>> +{
>> +    uint32_t aSign, bSign, cSign;
>> +    uint32_t aExp, bExp, cExp;
>> +
>> +    if (float32_is_any_nan(arg1) || float32_is_any_nan(arg2) ||
>> +        float32_is_any_nan(arg3)) {
>> +        return QUIET_NAN;
>> +    } else if (float32_is_infinity(arg1) && float32_is_zero(arg2)) {
>> +        return MUL_NAN;
>> +    } else if (float32_is_zero(arg1) && float32_is_infinity(arg2)) {
>> +        return MUL_NAN;
>> +    } else {
>> +        aSign = arg1 >> 31;
>> +        bSign = arg2 >> 31;
>> +        cSign = arg3 >> 31;
>> +
>> +        aExp = (arg1 >> 23) & 0xff;
>> +        bExp = (arg2 >> 23) & 0xff;
>> +        cExp = (arg3 >> 23) & 0xff;
>> +
>> +        if (flags & float_muladd_negate_c) {
> 
> flags here is muladd argument,
> 

I don't know what you mean by that.

However, I took this from softfloat's float32_muladd() to catch the case
of an invalid addition to return the correct NAN.

I thought of extending softfloat's muladd() to return a specializable
ADD_NAN to catch this case in the first place, but TriCore would be the
only target using it and I'm not sure if it's worth while.

Any comments on this idea?

Cheers,
    Bastian
Richard Henderson Nov. 8, 2016, 3:10 p.m. UTC | #3
On 11/08/2016 04:08 PM, Bastian Koppelmann wrote:
> On 11/08/2016 12:42 PM, Richard Henderson wrote:
>> On 11/07/2016 03:44 PM, Bastian Koppelmann wrote:
>>> Multiplies D[a] and D[b] and adds/subtracts the result to/from D[d].
>>> The result is put in D[c]. All operands are floating-point numbers.
>>>
>>> Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
>>> ---
>>>  target-tricore/fpu_helper.c | 93
>>> ++++++++++++++++++++++++++++++++++++++++++++-
>>>  target-tricore/helper.h     |  2 +
>>>  target-tricore/translate.c  |  8 ++++
>>>  3 files changed, 102 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/target-tricore/fpu_helper.c b/target-tricore/fpu_helper.c
>>> index f717b53..d530a0b 100644
>>> --- a/target-tricore/fpu_helper.c
>>> +++ b/target-tricore/fpu_helper.c
>>> @@ -21,7 +21,8 @@
>>>  #include "cpu.h"
>>>  #include "exec/helper-proto.h"
>>>
>>> -#define ADD_NAN   0x7cf00001
>>> +#define QUIET_NAN 0x7fc00000
>>> +#define ADD_NAN   0x7fc00001
>>>  #define DIV_NAN   0x7fc00008
>>>  #define MUL_NAN   0x7fc00002
>>>  #define FPU_FS PSW_USB_C
>>> @@ -47,6 +48,42 @@ static inline bool f_is_denormal(float32 arg)
>>>      return float32_is_zero_or_denormal(arg) && !float32_is_zero(arg);
>>>  }
>>>
>>> +static inline float32 f_maddsub_nan_result(float32 arg1, float32 arg2,
>>> +                                           float32 arg3, float32 result,
>>> +                                           uint32_t flags)
>>> +{
>>> +    uint32_t aSign, bSign, cSign;
>>> +    uint32_t aExp, bExp, cExp;
>>> +
>>> +    if (float32_is_any_nan(arg1) || float32_is_any_nan(arg2) ||
>>> +        float32_is_any_nan(arg3)) {
>>> +        return QUIET_NAN;
>>> +    } else if (float32_is_infinity(arg1) && float32_is_zero(arg2)) {
>>> +        return MUL_NAN;
>>> +    } else if (float32_is_zero(arg1) && float32_is_infinity(arg2)) {
>>> +        return MUL_NAN;
>>> +    } else {
>>> +        aSign = arg1 >> 31;
>>> +        bSign = arg2 >> 31;
>>> +        cSign = arg3 >> 31;
>>> +
>>> +        aExp = (arg1 >> 23) & 0xff;
>>> +        bExp = (arg2 >> 23) & 0xff;
>>> +        cExp = (arg3 >> 23) & 0xff;
>>> +
>>> +        if (flags & float_muladd_negate_c) {
>>
>> flags here is muladd argument,
>>
>
> I don't know what you mean by that.

I mean that the type you pass is not the type you check here.
They're different sets of bitmasks.

> I thought of extending softfloat's muladd() to return a specializable
> ADD_NAN to catch this case in the first place, but TriCore would be the
> only target using it and I'm not sure if it's worth while.
>
> Any comments on this idea?

I think just fixing up tricore is the way to go.


r~
diff mbox

Patch

diff --git a/target-tricore/fpu_helper.c b/target-tricore/fpu_helper.c
index f717b53..d530a0b 100644
--- a/target-tricore/fpu_helper.c
+++ b/target-tricore/fpu_helper.c
@@ -21,7 +21,8 @@ 
 #include "cpu.h"
 #include "exec/helper-proto.h"
 
-#define ADD_NAN   0x7cf00001
+#define QUIET_NAN 0x7fc00000
+#define ADD_NAN   0x7fc00001
 #define DIV_NAN   0x7fc00008
 #define MUL_NAN   0x7fc00002
 #define FPU_FS PSW_USB_C
@@ -47,6 +48,42 @@  static inline bool f_is_denormal(float32 arg)
     return float32_is_zero_or_denormal(arg) && !float32_is_zero(arg);
 }
 
+static inline float32 f_maddsub_nan_result(float32 arg1, float32 arg2,
+                                           float32 arg3, float32 result,
+                                           uint32_t flags)
+{
+    uint32_t aSign, bSign, cSign;
+    uint32_t aExp, bExp, cExp;
+
+    if (float32_is_any_nan(arg1) || float32_is_any_nan(arg2) ||
+        float32_is_any_nan(arg3)) {
+        return QUIET_NAN;
+    } else if (float32_is_infinity(arg1) && float32_is_zero(arg2)) {
+        return MUL_NAN;
+    } else if (float32_is_zero(arg1) && float32_is_infinity(arg2)) {
+        return MUL_NAN;
+    } else {
+        aSign = arg1 >> 31;
+        bSign = arg2 >> 31;
+        cSign = arg3 >> 31;
+
+        aExp = (arg1 >> 23) & 0xff;
+        bExp = (arg2 >> 23) & 0xff;
+        cExp = (arg3 >> 23) & 0xff;
+
+        if (flags & float_muladd_negate_c) {
+            cSign ^= 1;
+        }
+        if (((aExp == 0xff) || (bExp == 0xff)) && (cExp == 0xff)) {
+            if (aSign ^ bSign ^ cSign) {
+                return ADD_NAN;
+            }
+        }
+    }
+
+    return result;
+}
+
 static void f_update_psw_flags(CPUTriCoreState *env, uint8_t flags)
 {
     uint8_t some_excp = 0;
@@ -159,6 +196,60 @@  uint32_t helper_fdiv(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
     return (uint32_t)f_result;
 }
 
+uint32_t helper_fmadd(CPUTriCoreState *env, uint32_t r1,
+                      uint32_t r2, uint32_t r3)
+{
+    uint32_t flags;
+    float32 arg1 = make_float32(r1);
+    float32 arg2 = make_float32(r2);
+    float32 arg3 = make_float32(r3);
+    float32 f_result;
+
+    f_result = float32_muladd(arg1, arg2, arg3, 0, &env->fp_status);
+
+    flags = f_get_excp_flags(env);
+    if (flags) {
+        if (flags & float_flag_invalid) {
+            arg1 = float32_squash_input_denormal(arg1, &env->fp_status);
+            arg2 = float32_squash_input_denormal(arg2, &env->fp_status);
+            arg3 = float32_squash_input_denormal(arg3, &env->fp_status);
+            f_result = f_maddsub_nan_result(arg1, arg2, arg3, f_result, flags);
+        }
+        f_update_psw_flags(env, flags);
+    } else {
+        env->FPU_FS = 0;
+    }
+    return (uint32_t)f_result;
+}
+
+uint32_t helper_fmsub(CPUTriCoreState *env, uint32_t r1,
+                      uint32_t r2, uint32_t r3)
+{
+    uint32_t flags;
+    float32 arg1 = make_float32(r1);
+    float32 arg2 = make_float32(r2);
+    float32 arg3 = make_float32(r3);
+    float32 f_result;
+
+    f_result = float32_muladd(arg1, arg2, arg3, float_muladd_negate_product,
+                              &env->fp_status);
+
+    flags = f_get_excp_flags(env);
+    if (flags) {
+        if (flags & float_flag_invalid) {
+            arg1 = float32_squash_input_denormal(arg1, &env->fp_status);
+            arg2 = float32_squash_input_denormal(arg2, &env->fp_status);
+            arg3 = float32_squash_input_denormal(arg3, &env->fp_status);
+
+            f_result = f_maddsub_nan_result(arg1, arg2, arg3, f_result, flags);
+        }
+        f_update_psw_flags(env, flags);
+    } else {
+        env->FPU_FS = 0;
+    }
+    return (uint32_t)f_result;
+}
+
 uint32_t helper_fcmp(CPUTriCoreState *env, uint32_t r1, uint32_t r2)
 {
     uint32_t result, flags;
diff --git a/target-tricore/helper.h b/target-tricore/helper.h
index 467c880..c897a44 100644
--- a/target-tricore/helper.h
+++ b/target-tricore/helper.h
@@ -109,6 +109,8 @@  DEF_HELPER_3(fadd, i32, env, i32, i32)
 DEF_HELPER_3(fsub, i32, env, i32, i32)
 DEF_HELPER_3(fmul, i32, env, i32, i32)
 DEF_HELPER_3(fdiv, i32, env, i32, i32)
+DEF_HELPER_4(fmadd, i32, env, i32, i32, i32)
+DEF_HELPER_4(fmsub, i32, env, i32, i32, i32)
 DEF_HELPER_3(fcmp, i32, env, i32, i32)
 DEF_HELPER_2(ftoi, i32, env, i32)
 DEF_HELPER_2(itof, i32, env, i32)
diff --git a/target-tricore/translate.c b/target-tricore/translate.c
index 27c6d31..3fec353 100644
--- a/target-tricore/translate.c
+++ b/target-tricore/translate.c
@@ -7096,6 +7096,14 @@  static void decode_rrr_divide(CPUTriCoreState *env, DisasContext *ctx)
     case OPC2_32_RRR_SUB_F:
         gen_helper_fsub(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1], cpu_gpr_d[r3]);
         break;
+    case OPC2_32_RRR_MADD_F:
+        gen_helper_fmadd(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1],
+                         cpu_gpr_d[r2], cpu_gpr_d[r3]);
+        break;
+    case OPC2_32_RRR_MSUB_F:
+        gen_helper_fmsub(cpu_gpr_d[r4], cpu_env, cpu_gpr_d[r1],
+                         cpu_gpr_d[r2], cpu_gpr_d[r3]);
+        break;
     default:
         generate_trap(ctx, TRAPC_INSN_ERR, TIN2_IOPC);
     }