]> git.proxmox.com Git - qemu.git/blobdiff - target-ppc/op.c
target-ppc: convert crf related instructions to TCG
[qemu.git] / target-ppc / op.c
index c950579a1b536d07966b5ee8c86f4b2b2645e45a..d9676ba81eef2c354b7ea1c82b4c1d3edf41ef0f 100644 (file)
 #include "helper_regs.h"
 #include "op_helper.h"
 
-#define REG 0
-#include "op_template.h"
-
-#define REG 1
-#include "op_template.h"
-
-#define REG 2
-#include "op_template.h"
-
-#define REG 3
-#include "op_template.h"
-
-#define REG 4
-#include "op_template.h"
-
-#define REG 5
-#include "op_template.h"
-
-#define REG 6
-#include "op_template.h"
-
-#define REG 7
-#include "op_template.h"
-
-#define REG 8
-#include "op_template.h"
-
-#define REG 9
-#include "op_template.h"
-
-#define REG 10
-#include "op_template.h"
-
-#define REG 11
-#include "op_template.h"
-
-#define REG 12
-#include "op_template.h"
-
-#define REG 13
-#include "op_template.h"
-
-#define REG 14
-#include "op_template.h"
-
-#define REG 15
-#include "op_template.h"
-
-#define REG 16
-#include "op_template.h"
-
-#define REG 17
-#include "op_template.h"
-
-#define REG 18
-#include "op_template.h"
-
-#define REG 19
-#include "op_template.h"
-
-#define REG 20
-#include "op_template.h"
-
-#define REG 21
-#include "op_template.h"
-
-#define REG 22
-#include "op_template.h"
-
-#define REG 23
-#include "op_template.h"
-
-#define REG 24
-#include "op_template.h"
-
-#define REG 25
-#include "op_template.h"
-
-#define REG 26
-#include "op_template.h"
-
-#define REG 27
-#include "op_template.h"
-
-#define REG 28
-#include "op_template.h"
-
-#define REG 29
-#include "op_template.h"
-
-#define REG 30
-#include "op_template.h"
-
-#define REG 31
-#include "op_template.h"
-
-void OPPROTO op_print_mem_EA (void)
-{
-    do_print_mem_EA(T0);
-    RETURN();
-}
-
-/* PowerPC state maintenance operations */
-/* set_Rc0 */
-void OPPROTO op_set_Rc0 (void)
-{
-    env->crf[0] = T0 | xer_so;
-    RETURN();
-}
-
-/* Constants load */
-void OPPROTO op_reset_T0 (void)
-{
-    T0 = 0;
-    RETURN();
-}
-
-void OPPROTO op_set_T0 (void)
-{
-    T0 = (uint32_t)PARAM1;
-    RETURN();
-}
-
-#if defined(TARGET_PPC64)
-void OPPROTO op_set_T0_64 (void)
-{
-    T0 = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
-    RETURN();
-}
-#endif
-
-void OPPROTO op_set_T1 (void)
-{
-    T1 = (uint32_t)PARAM1;
-    RETURN();
-}
-
-#if defined(TARGET_PPC64)
-void OPPROTO op_set_T1_64 (void)
-{
-    T1 = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
-    RETURN();
-}
-#endif
-
-#if 0 // unused
-void OPPROTO op_set_T2 (void)
-{
-    T2 = (uint32_t)PARAM1;
-    RETURN();
-}
-#endif
-
-void OPPROTO op_move_T1_T0 (void)
-{
-    T1 = T0;
-    RETURN();
-}
-
-void OPPROTO op_move_T2_T0 (void)
-{
-    T2 = T0;
-    RETURN();
-}
-
-void OPPROTO op_moven_T2_T0 (void)
-{
-    T2 = ~T0;
-    RETURN();
-}
-
 /* Generate exceptions */
 void OPPROTO op_raise_exception_err (void)
 {
     do_raise_exception_err(PARAM1, PARAM2);
 }
 
-void OPPROTO op_update_nip (void)
-{
-    env->nip = (uint32_t)PARAM1;
-    RETURN();
-}
-
-#if defined(TARGET_PPC64)
-void OPPROTO op_update_nip_64 (void)
-{
-    env->nip = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
-    RETURN();
-}
-#endif
-
 void OPPROTO op_debug (void)
 {
     do_raise_exception(EXCP_DEBUG);
 }
 
-void OPPROTO op_exit_tb (void)
-{
-    EXIT_TB();
-}
-
 /* Load/store special registers */
-void OPPROTO op_load_cr (void)
-{
-    do_load_cr();
-    RETURN();
-}
-
-void OPPROTO op_store_cr (void)
-{
-    do_store_cr(PARAM1);
-    RETURN();
-}
-
-void OPPROTO op_load_cro (void)
-{
-    T0 = env->crf[PARAM1];
-    RETURN();
-}
-
-void OPPROTO op_store_cro (void)
-{
-    env->crf[PARAM1] = T0;
-    RETURN();
-}
-
-void OPPROTO op_load_xer_cr (void)
-{
-    T0 = (xer_so << 3) | (xer_ov << 2) | (xer_ca << 1);
-    RETURN();
-}
-
-void OPPROTO op_clear_xer_ov (void)
-{
-    xer_so = 0;
-    xer_ov = 0;
-    RETURN();
-}
-
-void OPPROTO op_clear_xer_ca (void)
-{
-    xer_ca = 0;
-    RETURN();
-}
-
-void OPPROTO op_load_xer_bc (void)
-{
-    T1 = xer_bc;
-    RETURN();
-}
-
-void OPPROTO op_store_xer_bc (void)
-{
-    xer_bc = T0;
-    RETURN();
-}
-
-void OPPROTO op_load_xer (void)
-{
-    T0 = hreg_load_xer(env);
-    RETURN();
-}
-
-void OPPROTO op_store_xer (void)
-{
-    hreg_store_xer(env, T0);
-    RETURN();
-}
-
 #if defined(TARGET_PPC64)
 void OPPROTO op_store_pri (void)
 {
@@ -421,30 +164,6 @@ void OPPROTO op_mask_spr (void)
     RETURN();
 }
 
-void OPPROTO op_load_lr (void)
-{
-    T0 = env->lr;
-    RETURN();
-}
-
-void OPPROTO op_store_lr (void)
-{
-    env->lr = T0;
-    RETURN();
-}
-
-void OPPROTO op_load_ctr (void)
-{
-    T0 = env->ctr;
-    RETURN();
-}
-
-void OPPROTO op_store_ctr (void)
-{
-    env->ctr = T0;
-    RETURN();
-}
-
 void OPPROTO op_load_tbl (void)
 {
     T0 = cpu_ppc_load_tbl(env);
@@ -585,59 +304,18 @@ void OPPROTO op_float_check_status (void)
 }
 #endif
 
-#if defined(WORDS_BIGENDIAN)
-#define WORD0 0
-#define WORD1 1
-#else
-#define WORD0 1
-#define WORD1 0
-#endif
 void OPPROTO op_load_fpscr_FT0 (void)
 {
     /* The 32 MSB of the target fpr are undefined.
      * They'll be zero...
      */
-    union {
-        float64 d;
-        struct {
-            uint32_t u[2];
-        } s;
-    } u;
-
-    u.s.u[WORD0] = 0;
-    u.s.u[WORD1] = env->fpscr;
-    FT0 = u.d;
-    RETURN();
-}
+    CPU_DoubleU u;
 
-void OPPROTO op_set_FT0 (void)
-{
-    union {
-        float64 d;
-        struct {
-            uint32_t u[2];
-        } s;
-    } u;
-
-    u.s.u[WORD0] = 0;
-    u.s.u[WORD1] = PARAM1;
+    u.l.upper = 0;
+    u.l.lower = env->fpscr;
     FT0 = u.d;
     RETURN();
 }
-#undef WORD0
-#undef WORD1
-
-void OPPROTO op_load_fpscr_T0 (void)
-{
-    T0 = (env->fpscr >> PARAM1) & 0xF;
-    RETURN();
-}
-
-void OPPROTO op_load_fpcc (void)
-{
-    T0 = fpscr_fpcc;
-    RETURN();
-}
 
 void OPPROTO op_fpscr_resetbit (void)
 {
@@ -658,8 +336,6 @@ void OPPROTO op_store_fpscr (void)
 }
 
 /* Branch */
-#define EIP env->nip
-
 void OPPROTO op_setlr (void)
 {
     env->lr = (uint32_t)PARAM1;
@@ -674,30 +350,6 @@ void OPPROTO op_setlr_64 (void)
 }
 #endif
 
-void OPPROTO op_goto_tb0 (void)
-{
-    GOTO_TB(op_goto_tb0, PARAM1, 0);
-}
-
-void OPPROTO op_goto_tb1 (void)
-{
-    GOTO_TB(op_goto_tb1, PARAM1, 1);
-}
-
-void OPPROTO op_b_T1 (void)
-{
-    env->nip = (uint32_t)(T1 & ~3);
-    RETURN();
-}
-
-#if defined (TARGET_PPC64)
-void OPPROTO op_b_T1_64 (void)
-{
-    env->nip = (uint64_t)(T1 & ~3);
-    RETURN();
-}
-#endif
-
 void OPPROTO op_jz_T0 (void)
 {
     if (!T0)
@@ -845,26 +497,28 @@ void OPPROTO op_dec_ctr (void)
 
 /***                           Integer arithmetic                          ***/
 /* add */
-void OPPROTO op_add (void)
-{
-    T0 += T1;
-    RETURN();
-}
-
 void OPPROTO op_check_addo (void)
 {
-    xer_ov = (((uint32_t)T2 ^ (uint32_t)T1 ^ UINT32_MAX) &
+    int ov = (((uint32_t)T2 ^ (uint32_t)T1 ^ UINT32_MAX) &
               ((uint32_t)T2 ^ (uint32_t)T0)) >> 31;
-    xer_so |= xer_ov;
+    if (ov) {
+        env->xer |= (1 << XER_OV) | (1 << XER_SO);
+    } else {
+        env->xer &= ~(1 << XER_OV);
+    }
     RETURN();
 }
 
 #if defined(TARGET_PPC64)
 void OPPROTO op_check_addo_64 (void)
 {
-    xer_ov = (((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) &
+    int ov = (((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) &
               ((uint64_t)T2 ^ (uint64_t)T0)) >> 63;
-    xer_so |= xer_ov;
+    if (ov) {
+        env->xer |= (1 << XER_OV) | (1 << XER_SO);
+    } else {
+        env->xer &= ~(1 << XER_OV);
+    }
     RETURN();
 }
 #endif
@@ -873,9 +527,9 @@ void OPPROTO op_check_addo_64 (void)
 void OPPROTO op_check_addc (void)
 {
     if (likely((uint32_t)T0 >= (uint32_t)T2)) {
-        xer_ca = 0;
+        env->xer &= ~(1 << XER_CA);
     } else {
-        xer_ca = 1;
+        env->xer |= (1 << XER_CA);
     }
     RETURN();
 }
@@ -884,9 +538,9 @@ void OPPROTO op_check_addc (void)
 void OPPROTO op_check_addc_64 (void)
 {
     if (likely((uint64_t)T0 >= (uint64_t)T2)) {
-        xer_ca = 0;
+        env->xer &= ~(1 << XER_CA);
     } else {
-        xer_ca = 1;
+        env->xer |= (1 << XER_CA);
     }
     RETURN();
 }
@@ -907,21 +561,12 @@ void OPPROTO op_adde_64 (void)
 }
 #endif
 
-/* add immediate */
-void OPPROTO op_addi (void)
-{
-    T0 += (int32_t)PARAM1;
-    RETURN();
-}
-
 /* add to minus one extended */
 void OPPROTO op_add_me (void)
 {
     T0 += xer_ca + (-1);
     if (likely((uint32_t)T1 != 0))
-        xer_ca = 1;
-    else
-        xer_ca = 0;
+        env->xer |= (1 << XER_CA);
     RETURN();
 }
 
@@ -930,9 +575,7 @@ void OPPROTO op_add_me_64 (void)
 {
     T0 += xer_ca + (-1);
     if (likely((uint64_t)T1 != 0))
-        xer_ca = 1;
-    else
-        xer_ca = 0;
+        env->xer |= (1 << XER_CA);
     RETURN();
 }
 #endif
@@ -1078,7 +721,11 @@ void OPPROTO op_mulli (void)
 /* multiply low word */
 void OPPROTO op_mullw (void)
 {
+#if defined(TARGET_PPC64)
+    T0 = (int64_t)(int32_t)T0 * (int64_t)(int32_t)T1;
+#else
     T0 = (int32_t)(T0 * T1);
+#endif
     RETURN();
 }
 
@@ -1137,20 +784,13 @@ void OPPROTO op_nego_64 (void)
 }
 #endif
 
-/* subtract from */
-void OPPROTO op_subf (void)
-{
-    T0 = T1 - T0;
-    RETURN();
-}
-
 /* subtract from carrying */
 void OPPROTO op_check_subfc (void)
 {
     if (likely((uint32_t)T0 > (uint32_t)T1)) {
-        xer_ca = 0;
+        env->xer &= ~(1 << XER_CA);
     } else {
-        xer_ca = 1;
+        env->xer |= (1 << XER_CA);
     }
     RETURN();
 }
@@ -1159,9 +799,9 @@ void OPPROTO op_check_subfc (void)
 void OPPROTO op_check_subfc_64 (void)
 {
     if (likely((uint64_t)T0 > (uint64_t)T1)) {
-        xer_ca = 0;
+        env->xer &= ~(1 << XER_CA);
     } else {
-        xer_ca = 1;
+        env->xer |= (1 << XER_CA);
     }
     RETURN();
 }
@@ -1187,9 +827,9 @@ void OPPROTO op_subfic (void)
 {
     T0 = (int32_t)PARAM1 + ~T0 + 1;
     if ((uint32_t)T0 <= (uint32_t)PARAM1) {
-        xer_ca = 1;
+        env->xer |= (1 << XER_CA);
     } else {
-        xer_ca = 0;
+        env->xer &= ~(1 << XER_CA);
     }
     RETURN();
 }
@@ -1199,9 +839,9 @@ void OPPROTO op_subfic_64 (void)
 {
     T0 = (int64_t)PARAM1 + ~T0 + 1;
     if ((uint64_t)T0 <= (uint64_t)PARAM1) {
-        xer_ca = 1;
+        env->xer |= (1 << XER_CA);
     } else {
-        xer_ca = 0;
+        env->xer &= ~(1 << XER_CA);
     }
     RETURN();
 }
@@ -1212,9 +852,7 @@ void OPPROTO op_subfme (void)
 {
     T0 = ~T0 + xer_ca - 1;
     if (likely((uint32_t)T0 != UINT32_MAX))
-        xer_ca = 1;
-    else
-        xer_ca = 0;
+        env->xer |= (1 << XER_CA);
     RETURN();
 }
 
@@ -1223,9 +861,7 @@ void OPPROTO op_subfme_64 (void)
 {
     T0 = ~T0 + xer_ca - 1;
     if (likely((uint64_t)T0 != UINT64_MAX))
-        xer_ca = 1;
-    else
-        xer_ca = 0;
+        env->xer |= (1 << XER_CA);
     RETURN();
 }
 #endif
@@ -1250,9 +886,9 @@ void OPPROTO op_subfze (void)
     T1 = ~T0;
     T0 = T1 + xer_ca;
     if ((uint32_t)T0 < (uint32_t)T1) {
-        xer_ca = 1;
+        env->xer |= (1 << XER_CA);
     } else {
-        xer_ca = 0;
+        env->xer &= ~(1 << XER_CA);
     }
     RETURN();
 }
@@ -1263,9 +899,9 @@ void OPPROTO op_subfze_64 (void)
     T1 = ~T0;
     T0 = T1 + xer_ca;
     if ((uint64_t)T0 < (uint64_t)T1) {
-        xer_ca = 1;
+        env->xer |= (1 << XER_CA);
     } else {
-        xer_ca = 0;
+        env->xer &= ~(1 << XER_CA);
     }
     RETURN();
 }
@@ -1285,132 +921,6 @@ void OPPROTO op_subfzeo_64 (void)
 }
 #endif
 
-/***                           Integer comparison                          ***/
-/* compare */
-void OPPROTO op_cmp (void)
-{
-    if ((int32_t)T0 < (int32_t)T1) {
-        T0 = 0x08;
-    } else if ((int32_t)T0 > (int32_t)T1) {
-        T0 = 0x04;
-    } else {
-        T0 = 0x02;
-    }
-    T0 |= xer_so;
-    RETURN();
-}
-
-#if defined(TARGET_PPC64)
-void OPPROTO op_cmp_64 (void)
-{
-    if ((int64_t)T0 < (int64_t)T1) {
-        T0 = 0x08;
-    } else if ((int64_t)T0 > (int64_t)T1) {
-        T0 = 0x04;
-    } else {
-        T0 = 0x02;
-    }
-    T0 |= xer_so;
-    RETURN();
-}
-#endif
-
-/* compare immediate */
-void OPPROTO op_cmpi (void)
-{
-    if ((int32_t)T0 < (int32_t)PARAM1) {
-        T0 = 0x08;
-    } else if ((int32_t)T0 > (int32_t)PARAM1) {
-        T0 = 0x04;
-    } else {
-        T0 = 0x02;
-    }
-    T0 |= xer_so;
-    RETURN();
-}
-
-#if defined(TARGET_PPC64)
-void OPPROTO op_cmpi_64 (void)
-{
-    if ((int64_t)T0 < (int64_t)((int32_t)PARAM1)) {
-        T0 = 0x08;
-    } else if ((int64_t)T0 > (int64_t)((int32_t)PARAM1)) {
-        T0 = 0x04;
-    } else {
-        T0 = 0x02;
-    }
-    T0 |= xer_so;
-    RETURN();
-}
-#endif
-
-/* compare logical */
-void OPPROTO op_cmpl (void)
-{
-    if ((uint32_t)T0 < (uint32_t)T1) {
-        T0 = 0x08;
-    } else if ((uint32_t)T0 > (uint32_t)T1) {
-        T0 = 0x04;
-    } else {
-        T0 = 0x02;
-    }
-    T0 |= xer_so;
-    RETURN();
-}
-
-#if defined(TARGET_PPC64)
-void OPPROTO op_cmpl_64 (void)
-{
-    if ((uint64_t)T0 < (uint64_t)T1) {
-        T0 = 0x08;
-    } else if ((uint64_t)T0 > (uint64_t)T1) {
-        T0 = 0x04;
-    } else {
-        T0 = 0x02;
-    }
-    T0 |= xer_so;
-    RETURN();
-}
-#endif
-
-/* compare logical immediate */
-void OPPROTO op_cmpli (void)
-{
-    if ((uint32_t)T0 < (uint32_t)PARAM1) {
-        T0 = 0x08;
-    } else if ((uint32_t)T0 > (uint32_t)PARAM1) {
-        T0 = 0x04;
-    } else {
-        T0 = 0x02;
-    }
-    T0 |= xer_so;
-    RETURN();
-}
-
-#if defined(TARGET_PPC64)
-void OPPROTO op_cmpli_64 (void)
-{
-    if ((uint64_t)T0 < (uint64_t)PARAM1) {
-        T0 = 0x08;
-    } else if ((uint64_t)T0 > (uint64_t)PARAM1) {
-        T0 = 0x04;
-    } else {
-        T0 = 0x02;
-    }
-    T0 |= xer_so;
-    RETURN();
-}
-#endif
-
-void OPPROTO op_isel (void)
-{
-    if (T0)
-        T0 = T1;
-    else
-        T0 = T2;
-    RETURN();
-}
-
 void OPPROTO op_popcntb (void)
 {
     do_popcntb();
@@ -1440,33 +950,6 @@ void OPPROTO op_andc (void)
     RETURN();
 }
 
-/* andi. */
-void OPPROTO op_andi_T0 (void)
-{
-    T0 &= (uint32_t)PARAM1;
-    RETURN();
-}
-
-void OPPROTO op_andi_T1 (void)
-{
-    T1 &= (uint32_t)PARAM1;
-    RETURN();
-}
-
-#if defined(TARGET_PPC64)
-void OPPROTO op_andi_T0_64 (void)
-{
-    T0 &= ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
-    RETURN();
-}
-
-void OPPROTO op_andi_T1_64 (void)
-{
-    T1 &= ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
-    RETURN();
-}
-#endif
-
 /* count leading zero */
 void OPPROTO op_cntlzw (void)
 {
@@ -1641,9 +1124,9 @@ void OPPROTO op_srawi (void)
 
     T0 = (int32_t)T0 >> PARAM1;
     if ((int32_t)T1 < 0 && (T1 & mask) != 0) {
-        xer_ca = 1;
+        env->xer |= (1 << XER_CA);
     } else {
-        xer_ca = 0;
+        env->xer &= ~(1 << XER_CA);
     }
     RETURN();
 }
@@ -1655,9 +1138,9 @@ void OPPROTO op_sradi (void)
 
     T0 = (int64_t)T0 >> PARAM1;
     if ((int64_t)T1 < 0 && ((uint64_t)T1 & mask) != 0) {
-        xer_ca = 1;
+        env->xer |= (1 << XER_CA);
     } else {
-        xer_ca = 0;
+        env->xer &= ~(1 << XER_CA);
     }
     RETURN();
 }
@@ -1698,12 +1181,6 @@ void OPPROTO op_sli_T0 (void)
     RETURN();
 }
 
-void OPPROTO op_sli_T1 (void)
-{
-    T1 = T1 << PARAM1;
-    RETURN();
-}
-
 void OPPROTO op_srl_T0_T1 (void)
 {
     T0 = (uint32_t)T0 >> T1;
@@ -1938,21 +1415,6 @@ void OPPROTO op_frim (void)
     RETURN();
 }
 
-/***                         Floating-Point compare                        ***/
-/* fcmpu */
-void OPPROTO op_fcmpu (void)
-{
-    do_fcmpu();
-    RETURN();
-}
-
-/* fcmpo */
-void OPPROTO op_fcmpo (void)
-{
-    do_fcmpo();
-    RETURN();
-}
-
 /***                         Floating-point move                           ***/
 /* fabs */
 void OPPROTO op_fabs (void)
@@ -2299,7 +1761,7 @@ void OPPROTO op_POWER_nabso (void)
     /* nabs never overflows */
     if (T0 > 0)
         T0 = -T0;
-    xer_ov = 0;
+    env->xer &= ~(1 << XER_OV);
     RETURN();
 }
 
@@ -2513,10 +1975,9 @@ void OPPROTO op_405_check_sat (void)
 void OPPROTO op_405_check_ovu (void)
 {
     if (likely(T0 >= T2)) {
-        xer_ov = 0;
+        env->xer &= ~(1 << XER_OV);
     } else {
-        xer_ov = 1;
-        xer_so = 1;
+        env->xer |= (1 << XER_OV) | (1 << XER_SO);
     }
     RETURN();
 }
@@ -2831,54 +2292,6 @@ void OPPROTO op_evcntlsw (void)
     RETURN();
 }
 
-void OPPROTO op_evand (void)
-{
-    T0_64 &= T1_64;
-    RETURN();
-}
-
-void OPPROTO op_evandc (void)
-{
-    T0_64 &= ~T1_64;
-    RETURN();
-}
-
-void OPPROTO op_evor (void)
-{
-    T0_64 |= T1_64;
-    RETURN();
-}
-
-void OPPROTO op_evxor (void)
-{
-    T0_64 ^= T1_64;
-    RETURN();
-}
-
-void OPPROTO op_eveqv (void)
-{
-    T0_64 = ~(T0_64 ^ T1_64);
-    RETURN();
-}
-
-void OPPROTO op_evnor (void)
-{
-    T0_64 = ~(T0_64 | T1_64);
-    RETURN();
-}
-
-void OPPROTO op_evorc (void)
-{
-    T0_64 |= ~T1_64;
-    RETURN();
-}
-
-void OPPROTO op_evnand (void)
-{
-    T0_64 = ~(T0_64 & T1_64);
-    RETURN();
-}
-
 void OPPROTO op_evsrws (void)
 {
     do_evsrws();
@@ -3241,27 +2654,21 @@ void OPPROTO op_efststeq (void)
 
 void OPPROTO op_efdsub (void)
 {
-    union {
-        uint64_t u;
-        float64 f;
-    } u1, u2;
-    u1.u = T0_64;
-    u2.u = T1_64;
-    u1.f = float64_sub(u1.f, u2.f, &env->spe_status);
-    T0_64 = u1.u;
+    CPU_DoubleU u1, u2;
+    u1.ll = T0_64;
+    u2.ll = T1_64;
+    u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
+    T0_64 = u1.ll;
     RETURN();
 }
 
 void OPPROTO op_efdadd (void)
 {
-    union {
-        uint64_t u;
-        float64 f;
-    } u1, u2;
-    u1.u = T0_64;
-    u2.u = T1_64;
-    u1.f = float64_add(u1.f, u2.f, &env->spe_status);
-    T0_64 = u1.u;
+    CPU_DoubleU u1, u2;
+    u1.ll = T0_64;
+    u2.ll = T1_64;
+    u1.d = float64_add(u1.d, u2.d, &env->spe_status);
+    T0_64 = u1.ll;
     RETURN();
 }
 
@@ -3297,27 +2704,21 @@ void OPPROTO op_efdneg (void)
 
 void OPPROTO op_efddiv (void)
 {
-    union {
-        uint64_t u;
-        float64 f;
-    } u1, u2;
-    u1.u = T0_64;
-    u2.u = T1_64;
-    u1.f = float64_div(u1.f, u2.f, &env->spe_status);
-    T0_64 = u1.u;
+    CPU_DoubleU u1, u2;
+    u1.ll = T0_64;
+    u2.ll = T1_64;
+    u1.d = float64_div(u1.d, u2.d, &env->spe_status);
+    T0_64 = u1.ll;
     RETURN();
 }
 
 void OPPROTO op_efdmul (void)
 {
-    union {
-        uint64_t u;
-        float64 f;
-    } u1, u2;
-    u1.u = T0_64;
-    u2.u = T1_64;
-    u1.f = float64_mul(u1.f, u2.f, &env->spe_status);
-    T0_64 = u1.u;
+    CPU_DoubleU u1, u2;
+    u1.ll = T0_64;
+    u2.ll = T1_64;
+    u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
+    T0_64 = u1.ll;
     RETURN();
 }