Removed the arch_irn_handler_t. This was just an additional redirection without
[libfirm] / ir / be / ia32 / bearch_ia32.c
index 5467086..7d9cf66 100644 (file)
@@ -214,11 +214,11 @@ static const arch_register_req_t *ia32_get_irn_reg_req(const void *self,
                                                        const ir_node *node,
                                                                                                           int pos)
 {
-       long node_pos = pos == -1 ? 0 : pos;
-       ir_mode *mode     = is_Block(node) ? NULL : get_irn_mode(node);
-       (void) self;
+       ir_mode *mode = get_irn_mode(node);
+       long    node_pos;
 
-       if (is_Block(node) || mode == mode_X) {
+       (void)self;
+       if (mode == mode_X || is_Block(node)) {
                return arch_no_register_req;
        }
 
@@ -226,11 +226,9 @@ static const arch_register_req_t *ia32_get_irn_reg_req(const void *self,
                return arch_no_register_req;
        }
 
+       node_pos = pos == -1 ? 0 : pos;
        if (is_Proj(node)) {
-               if(mode == mode_M)
-                       return arch_no_register_req;
-
-               if(pos >= 0) {
+               if (mode == mode_M || pos >= 0) {
                        return arch_no_register_req;
                }
 
@@ -240,7 +238,7 @@ static const arch_register_req_t *ia32_get_irn_reg_req(const void *self,
 
        if (is_ia32_irn(node)) {
                const arch_register_req_t *req;
-               if(pos >= 0)
+               if (pos >= 0)
                        req = get_ia32_in_req(node, pos);
                else
                        req = get_ia32_out_req(node, node_pos);
@@ -252,14 +250,13 @@ static const arch_register_req_t *ia32_get_irn_reg_req(const void *self,
 
        /* unknowns should be transformed already */
        assert(!is_Unknown(node));
-
        return arch_no_register_req;
 }
 
 static void ia32_set_irn_reg(const void *self, ir_node *irn,
                              const arch_register_t *reg)
 {
-       int                   pos = 0;
+       int    pos = 0;
        (void) self;
 
        if (get_irn_mode(irn) == mode_X) {
@@ -1459,6 +1456,7 @@ static void ia32_collect_frame_entity_nodes(ir_node *node, void *data)
                                   is_ia32_xStoreSimple(node) ||
                                   is_ia32_vfst(node) ||
                                   is_ia32_vfist(node) ||
+                                  is_ia32_vfisttp(node) ||
                               is_ia32_FnstCW(node));
 #endif
                }
@@ -1898,22 +1896,16 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type,
 }
 
 
-static const void *ia32_get_irn_ops(const arch_irn_handler_t *self,
-                                    const ir_node *irn)
+static const void *ia32_get_irn_ops(const ir_node *irn)
 {
-       (void) self;
        (void) irn;
        return &ia32_irn_ops;
 }
 
-const arch_irn_handler_t ia32_irn_handler = {
-       ia32_get_irn_ops
-};
-
-const arch_irn_handler_t *ia32_get_irn_handler(const void *self)
+arch_get_irn_ops_t *ia32_get_irn_handler(const void *self)
 {
        (void) self;
-       return &ia32_irn_handler;
+       return &ia32_get_irn_ops;
 }
 
 int ia32_to_appear_in_schedule(void *block_env, const ir_node *irn)
@@ -2068,37 +2060,139 @@ static ir_graph **ia32_get_irg_list(const void *self, ir_graph ***irg_list)
  */
 static int ia32_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
 {
-       ir_node *phi;
-
-       (void)sel;
-       (void)i;
-       (void)j;
+       ir_node *phi, *left;
+       ir_node *cmp = NULL;
+       ir_mode *cmp_mode;
+
+       if (ia32_cg_config.use_cmov) {
+               /* we can't handle psis with 64bit compares yet */
+               if (is_Proj(sel)) {
+                       cmp = get_Proj_pred(sel);
+                       if (is_Cmp(cmp)) {
+                               left     = get_Cmp_left(cmp);
+                               cmp_mode = get_irn_mode(left);
+                               if (!mode_is_float(cmp_mode) && get_mode_size_bits(cmp_mode) > 32)
+                                       return 0;
+                       } else {
+                               cmp = NULL;
+                       }
+               }
 
-       if(!ia32_cg_config.use_cmov) {
-               /* TODO: we could still handle abs(x)... */
-               return 0;
-       }
+               if (ia32_cg_config.use_sse2 && cmp != NULL) {
+                       pn_Cmp pn   = get_Proj_proj(sel);
+                       ir_node *cl = get_Cmp_left(cmp);
+                       ir_node *cr = get_Cmp_right(cmp);
+
+                       /* check the Phi nodes: no 64bit and no floating point cmov */
+                       for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+                               ir_mode *mode = get_irn_mode(phi);
+
+                               if (mode_is_float(mode)) {
+                                       /* check for Min, Max */
+                                       ir_node *t = get_Phi_pred(phi, i);
+                                       ir_node *f = get_Phi_pred(phi, j);
+                                       int res    = 0;
+
+                                       /* SSE2 supports Min & Max */
+                                       if (pn == pn_Cmp_Lt || pn == pn_Cmp_Le || pn == pn_Cmp_Ge || pn == pn_Cmp_Gt) {
+                                               if (cl == t && cr == f) {
+                                                       /* Psi(a <=/>= b, a, b) => MIN, MAX */
+                                                       res = 1;
+                                               } else if (cl == f && cr == t) {
+                                                       /* Psi(a <=/>= b, b, a) => MAX, MIN */
+                                                       res = 1;
+                                               }
+                                       }
+                                       if (! res)
+                                               return 0;
+
+                               } else if (get_mode_size_bits(mode) > 32)
+                                       return 0;
+                       }
+               } else {
+                       /* check the Phi nodes: no 64bit and no floating point cmov */
+                       for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+                               ir_mode *mode = get_irn_mode(phi);
 
-       /* we can't handle psis with 64bit compares yet */
-       if(is_Proj(sel)) {
-               ir_node *pred = get_Proj_pred(sel);
-               if(is_Cmp(pred)) {
-                       ir_node *left     = get_Cmp_left(pred);
-                       ir_mode *cmp_mode = get_irn_mode(left);
-                       if(!mode_is_float(cmp_mode) && get_mode_size_bits(cmp_mode) > 32)
-                               return 0;
+                               if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
+                                       return 0;
+                       }
                }
-       }
 
-       /* check the Phi nodes */
-       for (phi = phi_list; phi; phi = get_irn_link(phi)) {
-               ir_mode *mode = get_irn_mode(phi);
+               return 1;
+       } else {
+               ir_node *cl, *cr;
+               pn_Cmp  pn;
 
-               if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
+               /* No cmov, only some special cases */
+               if (! is_Proj(sel))
+                       return 0;
+               cmp = get_Proj_pred(sel);
+               if (! is_Cmp(cmp))
                        return 0;
-       }
 
-       return 1;
+               left     = get_Cmp_left(cmp);
+               cmp_mode = get_irn_mode(left);
+
+               /* Now some supported cases here */
+               pn = get_Proj_proj(sel);
+               cl = get_Cmp_left(cmp);
+               cr = get_Cmp_right(cmp);
+
+               for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+                       ir_mode *mode = get_irn_mode(phi);
+                       int res = 0;
+                       ir_node *t, *f;
+
+                       t = get_Phi_pred(phi, i);
+                       f = get_Phi_pred(phi, j);
+
+                       /* no floating point and no 64bit yet */
+                       if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
+                               return 0;
+
+                       if (is_Const(t) && is_Const(f)) {
+                               if ((is_Const_null(t) && is_Const_one(f)) || (is_Const_one(t) && is_Const_null(f))) {
+                                       /* always support Psi(x, C1, C2) */
+                                       res = 1;
+                               }
+                       } else if (pn == pn_Cmp_Lt || pn == pn_Cmp_Le || pn == pn_Cmp_Ge || pn == pn_Cmp_Gt) {
+                               if (0) {
+#if 0
+                               } else if (cl == t && cr == f) {
+                                       /* Psi(a <=/>= b, a, b) => Min, Max */
+                                       res = 1;
+                               } else if (cl == f && cr == t) {
+                                       /* Psi(a <=/>= b, b, a) => Max, Min */
+                                       res = 1;
+#endif
+                               } else if ((pn & pn_Cmp_Gt) && !mode_is_signed(mode) &&
+                                          is_Const(f) && is_Const_null(f) && is_Sub(t) &&
+                                          get_Sub_left(t) == cl && get_Sub_right(t) == cr) {
+                                       /* Psi(a >=u b, a - b, 0) unsigned Doz */
+                                       res = 1;
+                               } else if ((pn & pn_Cmp_Lt) && !mode_is_signed(mode) &&
+                                          is_Const(t) && is_Const_null(t) && is_Sub(f) &&
+                                          get_Sub_left(f) == cl && get_Sub_right(f) == cr) {
+                                       /* Psi(a <=u b, 0, a - b) unsigned Doz */
+                                       res = 1;
+                               } else if (is_Const(cr) && is_Const_null(cr)) {
+                                       if (cl == t && is_Minus(f) && get_Minus_op(f) == cl) {
+                                               /* Psi(a <=/>= 0 ? a : -a) Nabs/Abs */
+                                               res = 1;
+                                       } else if (cl == f && is_Minus(t) && get_Minus_op(t) == cl) {
+                                               /* Psi(a <=/>= 0 ? -a : a) Abs/Nabs */
+                                               res = 1;
+                                       }
+                               }
+                       }
+                       if (! res)
+                               return 0;
+               }
+               /* all checks passed */
+               return 1;
+       }
+       return 0;
 }
 
 /**