do not free the graph after emitting it (this should only change the peak memory...
[libfirm] / ir / be / ia32 / bearch_ia32.c
index 5076630..aa0d861 100644 (file)
@@ -50,6 +50,7 @@
 #include "irtools.h"
 #include "iroptimize.h"
 #include "instrument.h"
+#include "iropt_t.h"
 
 #include "../beabi.h"
 #include "../beirg.h"
@@ -443,8 +444,8 @@ static void ia32_build_between_type(void)
 {
 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
        if (! between_type) {
-               ir_type *old_bp_type   = new_type_primitive(IDENT("bp"), mode_Iu);
-               ir_type *ret_addr_type = new_type_primitive(IDENT("return_addr"), mode_Iu);
+               ir_type *old_bp_type   = new_type_primitive(mode_Iu);
+               ir_type *ret_addr_type = new_type_primitive(mode_Iu);
 
                between_type           = new_type_struct(IDENT("ia32_between_type"));
                old_bp_ent             = new_entity(between_type, IDENT("old_bp"), old_bp_type);
@@ -864,13 +865,14 @@ static void ia32_before_abi(void *self)
        ir_lower_mode_b(cg->irg, &lower_mode_b_config);
        if (cg->dump)
                be_dump(cg->irg, "-lower_modeb", dump_ir_block_graph_sched);
+
        if (cg->gprof) {
                if (mcount == NULL) {
-                       ir_type *tp = new_type_method(ID("FKT.mcount"), 0, 0);
+                       ir_type *tp = new_type_method(0, 0);
                        mcount = new_entity(get_glob_type(), ID("mcount"), tp);
                        /* FIXME: enter the right ld_ident here */
                        set_entity_ld_ident(mcount, get_entity_ident(mcount));
-                       set_entity_visibility(mcount, visibility_external_allocated);
+                       set_entity_visibility(mcount, ir_visibility_external);
                }
                instrument_initcall(cg->irg, mcount);
        }
@@ -1711,12 +1713,6 @@ static arch_env_t *ia32_init(FILE *file_handle)
        be_emit_cstring(".Ltext0:\n");
        be_emit_write_line();
 
-       /* we mark referenced global entities, so we can only emit those which
-        * are actually referenced. (Note: you mustn't use the type visited flag
-        * elsewhere in the backend)
-        */
-       inc_master_type_visited();
-
        return &isa->arch_env;
 }
 
@@ -1730,7 +1726,7 @@ static void ia32_done(void *self)
        ia32_isa_t *isa = self;
 
        /* emit now all global declarations */
-       be_gas_emit_decls(isa->arch_env.main_env, 1);
+       be_gas_emit_decls(isa->arch_env.main_env);
 
        pmap_destroy(isa->regs_16bit);
        pmap_destroy(isa->regs_8bit);
@@ -2130,264 +2126,243 @@ static void ia32_mark_remat(ir_node *node)
 }
 
 /**
- * Check for Abs or -Abs.
+ * Check if Mux(sel, t, f) would represent an Abs (or -Abs).
  */
-static int psi_is_Abs_or_Nabs(ir_node *cmp, ir_node *sel, ir_node *t, ir_node *f)
+static bool mux_is_abs(ir_node *sel, ir_node *mux_true, ir_node *mux_false)
 {
-       ir_node *l, *r;
+       ir_node *cmp_left;
+       ir_node *cmp_right;
+       ir_node *cmp;
        pn_Cmp  pnc;
 
-       if (cmp == NULL)
-               return 0;
+       if (!is_Proj(sel))
+               return false;
+       cmp = get_Proj_pred(sel);
+       if (!is_Cmp(cmp))
+               return false;
 
        /* must be <, <=, >=, > */
        pnc = get_Proj_proj(sel);
-       if (pnc != pn_Cmp_Ge && pnc != pn_Cmp_Gt &&
-               pnc != pn_Cmp_Le && pnc != pn_Cmp_Lt)
-               return 0;
+       switch (pnc) {
+       case pn_Cmp_Ge:
+       case pn_Cmp_Gt:
+       case pn_Cmp_Le:
+       case pn_Cmp_Lt:
+       case pn_Cmp_Uge:
+       case pn_Cmp_Ug:
+       case pn_Cmp_Ul:
+       case pn_Cmp_Ule:
+               break;
+       default:
+               return false;
+       }
 
-       l = get_Cmp_left(cmp);
-       r = get_Cmp_right(cmp);
+       if (!is_negated_value(mux_true, mux_false))
+               return false;
 
        /* must be x cmp 0 */
-       if ((l != t && l != f) || !is_Const(r) || !is_Const_null(r))
+       cmp_right = get_Cmp_right(cmp);
+       if (!is_Const(cmp_right) || !is_Const_null(cmp_right))
                return 0;
 
-       if ((!is_Minus(t) || get_Minus_op(t) != f) &&
-               (!is_Minus(f) || get_Minus_op(f) != t))
-               return 0;
-       return 1;
+       cmp_left = get_Cmp_left(cmp);
+       if (cmp_left != mux_true && cmp_left != mux_false)
+               return false;
+
+       return true;
 }
 
 /**
- * Check for Abs only
+ * Check if Mux(sel, mux_true, mux_false) would represent a Max or Min operation
  */
-static int psi_is_Abs(ir_node *cmp, ir_node *sel, ir_node *t, ir_node *f)
+static bool mux_is_float_min_max(ir_node *sel, ir_node *mux_true,
+                                 ir_node *mux_false)
 {
-       ir_node *l, *r;
+       ir_node *cmp_l;
+       ir_node *cmp_r;
+       ir_node *cmp;
        pn_Cmp  pnc;
 
-       if (cmp == NULL)
-               return 0;
-
-       /* must be <, <=, >=, > */
+       if (!is_Proj(sel))
+               return false;
+       cmp = get_Proj_pred(sel);
+       if (!is_Cmp(cmp))
+               return false;
+
+       cmp_l = get_Cmp_left(cmp);
+       cmp_r = get_Cmp_right(cmp);
+       if (!mode_is_float(get_irn_mode(cmp_l)))
+               return false;
+
+       /* check for min/max. They're defined as (C-Semantik):
+        *  min(a, b) = a < b ? a : b
+        *  or min(a, b) = a <= b ? a : b
+        *  max(a, b) = a > b ? a : b
+        *  or max(a, b) = a >= b ? a : b
+        * (Note we only handle float min/max here)
+        */
        pnc = get_Proj_proj(sel);
-       if (pnc != pn_Cmp_Ge && pnc != pn_Cmp_Gt &&
-               pnc != pn_Cmp_Le && pnc != pn_Cmp_Lt)
-               return 0;
+       switch (pnc) {
+       case pn_Cmp_Ge:
+       case pn_Cmp_Gt:
+               /* this is a max */
+               if (cmp_l == mux_true && cmp_r == mux_false)
+                       return true;
+               break;
+       case pn_Cmp_Le:
+       case pn_Cmp_Lt:
+               /* this is a min */
+               if (cmp_l == mux_true && cmp_r == mux_false)
+                       return true;
+               break;
+       case pn_Cmp_Uge:
+       case pn_Cmp_Ug:
+               /* this is a min */
+               if (cmp_l == mux_false && cmp_r == mux_true)
+                       return true;
+               break;
+       case pn_Cmp_Ule:
+       case pn_Cmp_Ul:
+               /* this is a max */
+               if (cmp_l == mux_false && cmp_r == mux_true)
+                       return true;
+               break;
 
-       l = get_Cmp_left(cmp);
-       r = get_Cmp_right(cmp);
+       default:
+               break;
+       }
 
-       /* must be x cmp 0 */
-       if ((l != t && l != f) || !is_Const(r) || !is_Const_null(r))
-               return 0;
+       return false;
+}
 
-       if ((!is_Minus(t) || get_Minus_op(t) != f) &&
-               (!is_Minus(f) || get_Minus_op(f) != t))
-               return 0;
+static bool mux_is_set(ir_node *sel, ir_node *mux_true, ir_node *mux_false)
+{
+       ir_mode *mode = get_irn_mode(mux_true);
+       (void) sel;
 
-       if (pnc & pn_Cmp_Gt) {
-               /* x >= 0 ? -x : x is NABS */
-               if (is_Minus(t))
-                       return 0;
-       } else {
-               /* x < 0 ? x : -x is NABS */
-               if (is_Minus(f))
-                       return 0;
+       if (!mode_is_int(mode) && !mode_is_reference(mode)
+                       && mode != mode_b)
+               return false;
+
+       if (is_Const(mux_true) && is_Const(mux_false)) {
+               /* we can create a set plus up two 3 instructions for any combination of constants */
+               return true;
        }
-       return 1;
+
+       return false;
 }
 
+static bool mux_is_float_const_const(ir_node *sel, ir_node *mux_true,
+                                     ir_node *mux_false)
+{
+       (void) sel;
 
-/**
- * Allows or disallows the creation of Mux nodes for the given Phi nodes.
- *
- * @param sel        A selector of a Cond.
- * @param phi_list   List of Phi nodes about to be converted (linked via get_Phi_next() field)
- * @param i          First data predecessor involved in if conversion
- * @param j          Second data predecessor involved in if conversion
- *
- * @return 1 if allowed, 0 otherwise
- */
-static int ia32_is_mux_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
+       if (!mode_is_float(get_irn_mode(mux_true)))
+               return false;
+
+       return is_Const(mux_true) && is_Const(mux_false);
+}
+
+static bool mux_is_doz(ir_node *sel, ir_node *mux_true, ir_node *mux_false)
 {
-       ir_node *phi;
        ir_node *cmp;
-       pn_Cmp  pn;
-       ir_node *cl, *cr;
-
-       /* we can't handle Muxs with 64bit compares yet */
-       if (is_Proj(sel)) {
-               cmp = get_Proj_pred(sel);
-               if (is_Cmp(cmp)) {
-                       ir_node *left     = get_Cmp_left(cmp);
-                       ir_mode *cmp_mode = get_irn_mode(left);
-                       if (!mode_is_float(cmp_mode) && get_mode_size_bits(cmp_mode) > 32) {
-                               /* 64bit Abs IS supported */
-                               for (phi = phi_list; phi; phi = get_Phi_next(phi)) {
-                                       ir_node *t = get_Phi_pred(phi, i);
-                                       ir_node *f = get_Phi_pred(phi, j);
-
-                                       if (! psi_is_Abs(cmp, sel, t, f))
-                                               return 0;
-                               }
-                               return 1;
-                       }
-               } else {
-                       /* we do not support nodes without Cmp yet */
-                       return 0;
-               }
-       } else {
-               /* we do not support nodes without Cmp yet */
-               return 0;
+       ir_node *cmp_left;
+       ir_node *cmp_right;
+       ir_mode *mode;
+       long     pn;
+
+       if (!is_Proj(sel))
+               return false;
+
+       cmp = get_Proj_pred(sel);
+       if (!is_Cmp(cmp))
+               return false;
+
+       mode = get_irn_mode(mux_true);
+       if (mode_is_signed(mode) || mode_is_float(mode))
+               return false;
+
+       pn        = get_Proj_proj(sel);
+       cmp_left  = get_Cmp_left(cmp);
+       cmp_right = get_Cmp_right(cmp);
+       if ((pn & pn_Cmp_Gt) &&
+               is_Const(mux_false) && is_Const_null(mux_false) && is_Sub(mux_true) &&
+               get_Sub_left(mux_true) == cmp_left &&
+               get_Sub_right(mux_true) == cmp_right) {
+               /* Mux(a >=u b, a - b, 0) unsigned Doz */
+               return true;
+       }
+       if ((pn & pn_Cmp_Lt) &&
+               is_Const(mux_true) && is_Const_null(mux_true) && is_Sub(mux_false) &&
+               get_Sub_left(mux_false) == cmp_left &&
+               get_Sub_right(mux_false) == cmp_right) {
+               /* Mux(a <=u b, 0, a - b) unsigned Doz */
+               return true;
        }
 
-       pn = get_Proj_proj(sel);
-       cl = get_Cmp_left(cmp);
-       cr = get_Cmp_right(cmp);
-
-       if (ia32_cg_config.use_cmov) {
-               if (ia32_cg_config.use_sse2) {
-                       /* check the Phi nodes: no 64bit and no floating point cmov */
-                       for (phi = phi_list; phi; phi = get_Phi_next(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);
-
-                                       /* 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) {
-                                                       /* Mux(a <=/>= b, a, b) => MIN, MAX */
-                                                       continue;
-                                               } else if (cl == f && cr == t) {
-                                                       /* Mux(a <=/>= b, b, a) => MAX, MIN */
-                                                       continue;
-                                               }
-                                       }
-                                       return 0;
-                               } else if (get_mode_size_bits(mode) > 32) {
-                                       /* no 64bit cmov */
-                                       return 0;
-                               }
-                       }
-               } else {
-                       /* check the Phi nodes: no 64bit and no floating point cmov */
-                       for (phi = phi_list; phi; phi = get_Phi_next(phi)) {
-                               ir_mode *mode = get_irn_mode(phi);
-
-                               if (mode_is_float(mode)) {
-                                       ir_node *t = get_Phi_pred(phi, i);
-                                       ir_node *f = get_Phi_pred(phi, j);
-
-                                       /* always support Mux(!float, C1, C2) */
-                                       if (is_Const(t) && is_Const(f) && !mode_is_float(get_irn_mode(cl))) {
-                                               switch (be_transformer) {
-                                               case TRANSFORMER_DEFAULT:
-                                                       /* always support Mux(!float, C1, C2) */
-                                                       continue;
-#ifdef FIRM_GRGEN_BE
-                                               case TRANSFORMER_PBQP:
-                                               case TRANSFORMER_RAND:
-                                                       /* no support for Mux(*, C1, C2) */
-                                                       return 0;
-#endif
-                                               default:
-                                                       panic("invalid transformer");
-                                               }
-                                       }
-                                       /* only abs or nabs supported */
-                                       if (! psi_is_Abs_or_Nabs(cmp, sel, t, f))
-                                               return 0;
-                               } else if (get_mode_size_bits(mode) > 32)
-                                       return 0;
-                       }
-               }
+       return false;
+}
 
-               return 1;
-       } else { /* No Cmov, only some special cases */
-
-               /* Now some supported cases here */
-               for (phi = phi_list; phi; phi = get_Phi_next(phi)) {
-                       ir_mode *mode = get_irn_mode(phi);
-                       ir_node *t, *f;
-
-                       t = get_Phi_pred(phi, i);
-                       f = get_Phi_pred(phi, j);
-
-                       if (mode_is_float(mode)) {
-                               /* always support Mux(!float, C1, C2) */
-                               if (is_Const(t) && is_Const(f) &&
-                                               !mode_is_float(get_irn_mode(cl))) {
-                                       switch (be_transformer) {
-                                               case TRANSFORMER_DEFAULT:
-                                                       /* always support Mux(!float, C1, C2) */
-                                                       continue;
+static int ia32_is_mux_allowed(ir_node *sel, ir_node *mux_false,
+                               ir_node *mux_true)
+{
+       ir_mode *mode;
+
+       /* we can handle Abs for all modes and compares */
+       if (mux_is_abs(sel, mux_true, mux_false))
+               return true;
+       /* we can handle Set for all modes and compares */
+       if (mux_is_set(sel, mux_true, mux_false))
+               return true;
+       /* SSE has own min/max operations */
+       if (ia32_cg_config.use_sse2
+                       && mux_is_float_min_max(sel, mux_true, mux_false))
+               return true;
+       /* we can handle Mux(?, Const[f], Const[f]) */
+       if (mux_is_float_const_const(sel, mux_true, mux_false)) {
 #ifdef FIRM_GRGEN_BE
-                                               case TRANSFORMER_PBQP:
-                                               case TRANSFORMER_RAND:
-                                                       /* no support for Mux(*, C1, C2) */
-                                                       return 0;
+               /* well, some code selectors can't handle it */
+               if (be_transformer != TRANSFORMER_PBQP
+                               || be_transformer != TRANSFORMER_RAND)
+                       return true;
+#else
+               return true;
 #endif
-                                               default:
-                                                       panic("invalid transformer");
-                                       }
-                               }
-                               /* only abs or nabs supported */
-                               if (! psi_is_Abs_or_Nabs(cmp, sel, t, f))
-                                       return 0;
-                       } else if (get_mode_size_bits(mode) > 32) {
-                               /* no 64bit yet */
-                               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 Mux(x, C1, C2) */
-                                       continue;
-                               }
-                       } else if (pn == pn_Cmp_Lt || pn == pn_Cmp_Le || pn == pn_Cmp_Ge || pn == pn_Cmp_Gt) {
-#if 0
-                               if (cl == t && cr == f) {
-                                       /* Mux(a <=/>= b, a, b) => Min, Max */
-                                       continue;
-                               }
-                               if (cl == f && cr == t) {
-                                       /* Mux(a <=/>= b, b, a) => Max, Min */
-                                       continue;
-                               }
-#endif
-                               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) {
-                                       /* Mux(a >=u b, a - b, 0) unsigned Doz */
-                                       continue;
-                               }
-                               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) {
-                                       /* Mux(a <=u b, 0, a - b) unsigned Doz */
-                                       continue;
-                               }
-                               if (is_Const(cr) && is_Const_null(cr)) {
-                                       if (cl == t && is_Minus(f) && get_Minus_op(f) == cl) {
-                                               /* Mux(a <=/>= 0 ? a : -a) Nabs/Abs */
-                                               continue;
-                                       } else if (cl == f && is_Minus(t) && get_Minus_op(t) == cl) {
-                                               /* Mux(a <=/>= 0 ? -a : a) Abs/Nabs */
-                                               continue;
-                                       }
-                               }
-                       }
-                       return 0;
+       /* no support for 64bit inputs to cmov */
+       mode = get_irn_mode(mux_true);
+       if (get_mode_size_bits(mode) > 32)
+               return false;
+       /* we can't handle MuxF yet */
+       if (mode_is_float(mode))
+               return false;
+
+       if (mux_is_doz(sel, mux_true, mux_false))
+               return true;
+
+       /* Check Cmp before the node */
+       if (is_Proj(sel)) {
+               ir_node *cmp = get_Proj_pred(sel);
+               if (is_Cmp(cmp)) {
+                       ir_mode *cmp_mode = get_irn_mode(get_Cmp_left(cmp));
+
+                       /* we can't handle 64bit compares */
+                       if (get_mode_size_bits(cmp_mode) > 32)
+                               return false;
+
+                       /* we can't handle float compares */
+                       if (mode_is_float(cmp_mode))
+                               return false;
                }
-               /* all checks passed */
-               return 1;
        }
-       return 0;
+
+       /* did we disable cmov generation? */
+       if (!ia32_cg_config.use_cmov)
+               return false;
+
+       /* we can use a cmov */
+       return true;
 }
 
 static asm_constraint_flags_t ia32_parse_asm_constraint(const char **c)
@@ -2477,15 +2452,14 @@ static const backend_params *ia32_get_libfirm_params(void)
 }
 
 static const lc_opt_enum_int_items_t gas_items[] = {
-       { "elf",     GAS_FLAVOUR_ELF },
-       { "mingw",   GAS_FLAVOUR_MINGW  },
-       { "yasm",    GAS_FLAVOUR_YASM   },
-       { "macho",   GAS_FLAVOUR_MACH_O },
-       { NULL,      0 }
+       { "elf",   OBJECT_FILE_FORMAT_ELF    },
+       { "mingw", OBJECT_FILE_FORMAT_COFF   },
+       { "macho", OBJECT_FILE_FORMAT_MACH_O },
+       { NULL,    0 }
 };
 
 static lc_opt_enum_int_var_t gas_var = {
-       (int*) &be_gas_flavour, gas_items
+       (int*) &be_gas_object_file_format, gas_items
 };
 
 #ifdef FIRM_GRGEN_BE