diff mbox

[17/37] target-ppc: Introduce DFP Add

Message ID 1397832641-10254-18-git-send-email-tommusta@gmail.com
State New
Headers show

Commit Message

Tom Musta April 18, 2014, 2:50 p.m. UTC
Add emulation of the PowerPC Decimal Floating Point Add instructions dadd[q][.]

Various GCC unused annotations are removed since it is now safe to remove them.

Signed-off-by: Tom Musta <tommusta@gmail.com>
---
 target-ppc/dfp_helper.c |  129 +++++++++++++++++++++++++++++++++++++++++++++--
 target-ppc/helper.h     |    2 +
 target-ppc/translate.c  |    7 ++-
 3 files changed, 132 insertions(+), 6 deletions(-)

Comments

Richard Henderson April 18, 2014, 6:16 p.m. UTC | #1
On 04/18/2014 07:50 AM, Tom Musta wrote:
> +PPC_DFP_PostProc ADD_PPs[] = {

static const.


r~
Richard Henderson April 18, 2014, 7:10 p.m. UTC | #2
On 04/18/2014 07:50 AM, Tom Musta wrote:
> +__attribute__ ((unused))
> +static void dfp_run_post_processors(struct PPC_DFP *dfp,
> +                PPC_DFP_PostProc post_processors[], const size_t n)
> +{
> +    int i;
> +
> +    for (i = 0; i < n; i++) {
> +        post_processors[i](dfp);
> +    }
> +}

...

> +PPC_DFP_PostProc ADD_PPs[] = {
> +    dfp_set_FPRF_from_FRT,
> +    dfp_check_for_OX,
> +    dfp_check_for_UX,
> +    dfp_check_for_XX,
> +    dfp_check_for_VXSNAN,
> +    dfp_check_for_VXISI_add,
> +};

Is this really any better than

static void ADD_PPs(struct PPC_DFP *dfp)
{
    dfp_set_FPRF_from_FRT(dfp);
    dfp_check_for_OX(dfp);
    dfp_check_for_UX(dfp);
    dfp_check_for_XX(dfp);
    dfp_check_for_VXSNAN(dfp);
    dfp_check_for_VXISI_add(dfp);
}

The forms seem equally readable to me, with the advantage that we'll get good
branch prediction on direct subroutine calls.  And if the compiler decides that
inlining is profitable, it'll have a chance.


r~
Tom Musta April 18, 2014, 7:46 p.m. UTC | #3
On 4/18/2014 2:10 PM, Richard Henderson wrote:
> On 04/18/2014 07:50 AM, Tom Musta wrote:
[...]
> 
> The forms seem equally readable to me, with the advantage that we'll get good
> branch prediction on direct subroutine calls.  And if the compiler decides that
> inlining is profitable, it'll have a chance.

Thank you for the feedback Richard.  I will address these with a V2.
diff mbox

Patch

diff --git a/target-ppc/dfp_helper.c b/target-ppc/dfp_helper.c
index 0c11696..100b0d7 100644
--- a/target-ppc/dfp_helper.c
+++ b/target-ppc/dfp_helper.c
@@ -77,7 +77,6 @@  static void dfp_prepare_rounding_mode(decContext *context, uint64_t fpscr)
     decContextSetRounding(context, rnd);
 }
 
-__attribute__ ((unused))
 static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a,
                 uint64_t *b, CPUPPCState *env)
 {
@@ -102,7 +101,6 @@  static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a,
     }
 }
 
-__attribute__ ((unused))
 static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a,
                 uint64_t *b, CPUPPCState *env)
 {
@@ -150,7 +148,6 @@  static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a,
 #define FP_VE       (1ull << FPSCR_VE)
 #define FP_FI       (1ull << FPSCR_FI)
 
-__attribute__ ((unused))
 static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag,
                 uint64_t enabled)
 {
@@ -162,7 +159,103 @@  static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag,
 
 typedef void (*PPC_DFP_PostProc)(struct PPC_DFP *);
 
-__attribute__ ((unused))
+static void dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP *dfp,
+                decContext *context)
+{
+    uint64_t fprf = 0;
+
+    /* construct FPRF */
+    switch (decNumberClass(&dfp->t, context)) {
+    case DEC_CLASS_SNAN:
+        fprf = 0x01;
+        break;
+    case DEC_CLASS_QNAN:
+        fprf = 0x11;
+        break;
+    case DEC_CLASS_NEG_INF:
+        fprf = 0x09;
+        break;
+    case DEC_CLASS_NEG_NORMAL:
+        fprf = 0x08;
+        break;
+    case DEC_CLASS_NEG_SUBNORMAL:
+        fprf = 0x18;
+        break;
+    case DEC_CLASS_NEG_ZERO:
+        fprf = 0x12;
+        break;
+    case DEC_CLASS_POS_ZERO:
+        fprf = 0x02;
+        break;
+    case DEC_CLASS_POS_SUBNORMAL:
+        fprf = 0x14;
+        break;
+    case DEC_CLASS_POS_NORMAL:
+        fprf = 0x04;
+        break;
+    case DEC_CLASS_POS_INF:
+        fprf = 0x05;
+        break;
+    default:
+        assert(0); /* should never get here */
+    }
+    dfp->env->fpscr &= ~(0x1F << 12);
+    dfp->env->fpscr |= (fprf << 12);
+}
+
+static void dfp_set_FPRF_from_FRT(struct PPC_DFP *dfp)
+{
+    dfp_set_FPRF_from_FRT_with_context(dfp, &dfp->context);
+}
+
+static void dfp_check_for_OX(struct PPC_DFP *dfp)
+{
+    if (dfp->context.status & DEC_Overflow) {
+        dfp_set_FPSCR_flag(dfp, FP_OX, FP_OE);
+    }
+}
+
+static void dfp_check_for_UX(struct PPC_DFP *dfp)
+{
+    if (dfp->context.status & DEC_Underflow) {
+        dfp_set_FPSCR_flag(dfp, FP_UX, FP_UE);
+    }
+}
+
+static void dfp_check_for_XX(struct PPC_DFP *dfp)
+{
+    if (dfp->context.status & DEC_Inexact) {
+        dfp_set_FPSCR_flag(dfp, FP_XX | FP_FI, FP_XE);
+    }
+}
+
+static void dfp_check_for_VXSNAN(struct PPC_DFP *dfp)
+{
+    if (dfp->context.status & DEC_Invalid_operation) {
+        if (decNumberIsSNaN(&dfp->a) || decNumberIsSNaN(&dfp->b)) {
+            dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXSNAN, FP_VE);
+        }
+    }
+}
+
+static void dfp_check_for_VXISI(struct PPC_DFP *dfp, int testForSameSign)
+{
+    if (dfp->context.status & DEC_Invalid_operation) {
+        if (decNumberIsInfinite(&dfp->a) && decNumberIsInfinite(&dfp->b)) {
+            int same = decNumberClass(&dfp->a, &dfp->context) ==
+                       decNumberClass(&dfp->b, &dfp->context);
+            if ((same && testForSameSign) || (!same && !testForSameSign)) {
+                dfp_set_FPSCR_flag(dfp, FP_VX | FP_VXISI, FP_VE);
+            }
+        }
+    }
+}
+
+static void dfp_check_for_VXISI_add(struct PPC_DFP *dfp)
+{
+    dfp_check_for_VXISI(dfp, 0);
+}
+
 static void dfp_run_post_processors(struct PPC_DFP *dfp,
                 PPC_DFP_PostProc post_processors[], const size_t n)
 {
@@ -172,3 +265,31 @@  static void dfp_run_post_processors(struct PPC_DFP *dfp,
         post_processors[i](dfp);
     }
 }
+
+#define DFP_HELPER_TAB(op, dnop, postprocs, size)                              \
+void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b)      \
+{                                                                              \
+    struct PPC_DFP dfp;                                                        \
+    dfp_prepare_decimal##size(&dfp, a, b, env);                                \
+    dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context);                                \
+    decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \
+    dfp_run_post_processors(&dfp, postprocs, ARRAY_SIZE(postprocs));           \
+    if (size == 64) {                                                          \
+        t[0] = dfp.t64[0];                                                     \
+    } else if (size == 128) {                                                  \
+        t[0] = dfp.t64[HI_IDX];                                                \
+        t[1] = dfp.t64[LO_IDX];                                                \
+    }                                                                          \
+}
+
+PPC_DFP_PostProc ADD_PPs[] = {
+    dfp_set_FPRF_from_FRT,
+    dfp_check_for_OX,
+    dfp_check_for_UX,
+    dfp_check_for_XX,
+    dfp_check_for_VXSNAN,
+    dfp_check_for_VXISI_add,
+};
+
+DFP_HELPER_TAB(dadd, decNumberAdd, ADD_PPs, 64)
+DFP_HELPER_TAB(daddq, decNumberAdd, ADD_PPs, 128)
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 1bebc8e..337c005 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -618,4 +618,6 @@  DEF_HELPER_3(store_601_batu, void, env, i32, tl)
 #define dh_ctype_fprp uint64_t *
 #define dh_is_signed_fprp dh_is_signed_ptr
 
+DEF_HELPER_4(dadd, void, env, fprp, fprp, fprp)
+DEF_HELPER_4(daddq, void, env, fprp, fprp, fprp)
 #include "exec/def-helper.h"
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 12aee63..4550667 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -8197,7 +8197,6 @@  static inline TCGv_ptr gen_fprp_ptr(int reg)
 }
 
 #if defined(TARGET_PPC64)
-__attribute__ ((unused))
 static void gen_set_cr6_from_fpscr(DisasContext *ctx)
 {
     TCGv_i32 tmp = tcg_temp_new_i32();
@@ -8206,7 +8205,6 @@  static void gen_set_cr6_from_fpscr(DisasContext *ctx)
     tcg_temp_free_i32(tmp);
 }
 #else
-__attribute__ ((unused))
 static void gen_set_cr6_from_fpscr(DisasContext *ctx)
 {
         tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28);
@@ -8358,6 +8356,9 @@  static void gen_##name(DisasContext *ctx)          \
     tcg_temp_free_i32(i32);                        \
 }
 
+GEN_DFP_T_A_B_Rc(dadd)
+GEN_DFP_T_A_B_Rc(daddq)
+
 /***                           SPE extension                               ***/
 /* Register moves */
 
@@ -11285,6 +11286,8 @@  _GEN_DFP_LONGx2(name, op1, op2, 0x00000000)
 #define GEN_DFP_Tp_Ap_SH_Rc(name, op1, op2) \
 _GEN_DFP_QUADx2(name, op1, op2, 0x00210000)
 
+GEN_DFP_T_A_B_Rc(dadd, 0x02, 0x00),
+GEN_DFP_Tp_Ap_Bp_Rc(daddq, 0x02, 0x00),
 #undef GEN_SPE
 #define GEN_SPE(name0, name1, opc2, opc3, inval0, inval1, type) \
     GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, PPC_NONE)