HACK: Prevent folding reload AM when the node already has a "real" memory input....
[libfirm] / ir / be / ia32 / bearch_ia32.c
index fdf9abf..1ca37fc 100644 (file)
@@ -70,6 +70,7 @@
 #include "../begnuas.h"
 #include "../bestate.h"
 #include "../beflags.h"
+#include "../betranshlp.h"
 
 #include "bearch_ia32_t.h"
 
@@ -180,7 +181,8 @@ ir_node *ia32_new_Fpu_truncate(ia32_code_gen_t *cg) {
 /**
  * Returns the admissible noreg register node for input register pos of node irn.
  */
-ir_node *ia32_get_admissible_noreg(ia32_code_gen_t *cg, ir_node *irn, int pos) {
+static ir_node *ia32_get_admissible_noreg(ia32_code_gen_t *cg, ir_node *irn, int pos)
+{
        const arch_register_req_t *req;
 
        req = arch_get_register_req(cg->arch_env, irn, pos);
@@ -319,9 +321,15 @@ static arch_irn_class_t ia32_classify(const ir_node *irn) {
        if (is_ia32_St(irn))
                classification |= arch_irn_class_store;
 
-       if (is_ia32_need_stackent(irn))
+       if (is_ia32_is_reload(irn))
                classification |= arch_irn_class_reload;
 
+       if (is_ia32_is_spill(irn))
+               classification |= arch_irn_class_spill;
+
+       if (is_ia32_is_remat(irn))
+               classification |= arch_irn_class_remat;
+
        return classification;
 }
 
@@ -385,6 +393,9 @@ static void ia32_set_frame_offset(ir_node *irn, int bias)
 
 static int ia32_get_sp_bias(const ir_node *node)
 {
+       if (is_ia32_Call(node))
+               return -(int)get_ia32_call_attr_const(node)->pop;
+
        if (is_ia32_Push(node))
                return 4;
 
@@ -538,8 +549,8 @@ static void ia32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_
  */
 static void *ia32_abi_init(const be_abi_call_t *call, const arch_env_t *aenv, ir_graph *irg)
 {
-       ia32_abi_env_t *env    = xmalloc(sizeof(env[0]));
-       be_abi_call_flags_t fl = be_abi_call_get_flags(call);
+       ia32_abi_env_t      *env = XMALLOC(ia32_abi_env_t);
+       be_abi_call_flags_t  fl  = be_abi_call_get_flags(call);
        env->flags = fl.bits;
        env->irg   = irg;
        env->aenv  = aenv;
@@ -795,48 +806,69 @@ static ir_mode *get_spill_mode(const ir_node *node)
  */
 static int ia32_is_spillmode_compatible(const ir_mode *mode, const ir_mode *spillmode)
 {
-       if(mode_is_float(mode)) {
-               return mode == spillmode;
-       } else {
-               return 1;
-       }
+       return !mode_is_float(mode) || mode == spillmode;
 }
 
 /**
  * Check if irn can load its operand at position i from memory (source addressmode).
- * @param self   Pointer to irn ops itself
  * @param irn    The irn to be checked
  * @param i      The operands position
  * @return Non-Zero if operand can be loaded
  */
-static int ia32_possible_memory_operand(const ir_node *irn, unsigned int i) {
-       ir_node *op = get_irn_n(irn, i);
-       const ir_mode *mode = get_irn_mode(op);
+static int ia32_possible_memory_operand(const ir_node *irn, unsigned int i)
+{
+       ir_node       *op        = get_irn_n(irn, i);
+       const ir_mode *mode      = get_irn_mode(op);
        const ir_mode *spillmode = get_spill_mode(op);
 
-       if (
-               (i != n_ia32_binary_left && i != n_ia32_binary_right) || /* a "real" operand position must be requested */
-               ! is_ia32_irn(irn)                                    ||  /* must be an ia32 irn */
-               get_ia32_am_arity(irn) != ia32_am_binary              ||  /* must be a binary operation TODO is this necessary? */
-               get_ia32_op_type(irn) != ia32_Normal                  ||  /* must not already be a addressmode irn */
-               ! (get_ia32_am_support(irn) & ia32_am_Source)         ||  /* must be capable of source addressmode */
-               ! ia32_is_spillmode_compatible(mode, spillmode)       ||
-               is_ia32_use_frame(irn))                                  /* must not already use frame */
+       if (!is_ia32_irn(irn)                              ||  /* must be an ia32 irn */
+           get_ia32_op_type(irn) != ia32_Normal           ||  /* must not already be a addressmode irn */
+           !ia32_is_spillmode_compatible(mode, spillmode) ||
+           is_ia32_use_frame(irn))                            /* must not already use frame */
                return 0;
 
-       if (i == n_ia32_binary_left) {
-               const arch_register_req_t *req;
-               if(!is_ia32_commutative(irn))
+       switch (get_ia32_am_support(irn)) {
+               case ia32_am_none:
                        return 0;
-               /* we can't swap left/right for limited registers
-                * (As this (currently) breaks constraint handling copies)
-                */
-               req = get_ia32_in_req(irn, n_ia32_binary_left);
-               if (req->type & arch_register_req_type_limited) {
-                       return 0;
-               }
+
+               case ia32_am_unary:
+                       if (i != n_ia32_unary_op)
+                               return 0;
+                       break;
+
+               case ia32_am_binary:
+                       switch (i) {
+                               case n_ia32_binary_left: {
+                                       const arch_register_req_t *req;
+                                       if (!is_ia32_commutative(irn))
+                                               return 0;
+
+                                       /* we can't swap left/right for limited registers
+                                        * (As this (currently) breaks constraint handling copies)
+                                        */
+                                       req = get_ia32_in_req(irn, n_ia32_binary_left);
+                                       if (req->type & arch_register_req_type_limited)
+                                               return 0;
+                                       break;
+                               }
+
+                               case n_ia32_binary_right:
+                                       break;
+
+                               default:
+                                       return 0;
+                       }
+                       break;
+
+               default:
+                       panic("Unknown AM type");
        }
 
+       /* HACK: must not already use "real" memory.
+        * This can happen for Call and Div */
+       if (!is_NoMem(get_irn_n(irn, n_ia32_mem)))
+               return 0;
+
        return 1;
 }
 
@@ -846,14 +878,8 @@ static void ia32_perform_memory_operand(ir_node *irn, ir_node *spill,
        ir_mode *load_mode;
        ir_mode *dest_op_mode;
 
-       ia32_code_gen_t *cg = ia32_current_cg;
-
        assert(ia32_possible_memory_operand(irn, i) && "Cannot perform memory operand change");
 
-       if (i == n_ia32_binary_left) {
-               ia32_swap_left_right(irn);
-       }
-
        set_ia32_op_type(irn, ia32_AddrModeS);
 
        load_mode    = get_irn_mode(get_irn_n(irn, i));
@@ -864,15 +890,20 @@ static void ia32_perform_memory_operand(ir_node *irn, ir_node *spill,
        set_ia32_use_frame(irn);
        set_ia32_need_stackent(irn);
 
-       set_irn_n(irn, n_ia32_base, get_irg_frame(get_irn_irg(irn)));
-       set_irn_n(irn, n_ia32_binary_right, ia32_get_admissible_noreg(cg, irn, n_ia32_binary_right));
-       set_irn_n(irn, n_ia32_mem, spill);
-       set_ia32_is_reload(irn);
-
-       /* immediates are only allowed on the right side */
-       if (i == n_ia32_binary_left && is_ia32_Immediate(get_irn_n(irn, n_ia32_binary_left))) {
+       if (i == n_ia32_binary_left                    &&
+           get_ia32_am_support(irn) == ia32_am_binary &&
+           /* immediates are only allowed on the right side */
+           !is_ia32_Immediate(get_irn_n(irn, n_ia32_binary_right))) {
                ia32_swap_left_right(irn);
+               i = n_ia32_binary_right;
        }
+
+       assert(is_NoMem(get_irn_n(irn, n_ia32_mem)));
+
+       set_irn_n(irn, n_ia32_base, get_irg_frame(get_irn_irg(irn)));
+       set_irn_n(irn, n_ia32_mem,  spill);
+       set_irn_n(irn, i,           ia32_get_admissible_noreg(ia32_current_cg, irn, i));
+       set_ia32_is_reload(irn);
 }
 
 static const be_abi_callbacks_t ia32_abi_callbacks = {
@@ -920,7 +951,7 @@ static ir_entity *mcount = NULL;
 static void ia32_before_abi(void *self) {
        lower_mode_b_config_t lower_mode_b_config = {
                mode_Iu,  /* lowered mode */
-               mode_Bu,  /* prefered mode for set */
+               mode_Bu,  /* preferred mode for set */
                0,        /* don't lower direct compares */
        };
        ia32_code_gen_t *cg = self;
@@ -972,13 +1003,8 @@ static void ia32_prepare_graph(void *self) {
 #ifdef FIRM_GRGEN_BE
                case TRANSFORMER_PBQP:
                case TRANSFORMER_RAND:
-                       // disable CSE, because of two-step node-construction
-                       set_opt_cse(0);
-
                        /* transform nodes into assembler instructions by PBQP magic */
                        ia32_transform_graph_by_pbqp(cg);
-
-                       set_opt_cse(1);
                        break;
 #endif
 
@@ -1011,7 +1037,7 @@ static void ia32_before_sched(void *self) {
        (void) self;
 }
 
-static void turn_back_am(ir_node *node)
+ir_node *turn_back_am(ir_node *node)
 {
        ir_graph *irg   = current_ir_graph;
        dbg_info *dbgi  = get_irn_dbg_info(node);
@@ -1019,42 +1045,34 @@ static void turn_back_am(ir_node *node)
        ir_node  *base  = get_irn_n(node, n_ia32_base);
        ir_node  *index = get_irn_n(node, n_ia32_index);
        ir_node  *mem   = get_irn_n(node, n_ia32_mem);
-       ir_node  *noreg = ia32_new_NoReg_gp(ia32_current_cg);
-       ir_node  *load;
-       ir_node  *load_res;
-       ir_node  *mem_proj;
-       const ir_edge_t *edge;
+       ir_node  *noreg;
 
-       load     = new_rd_ia32_Load(dbgi, irg, block, base, index, mem);
-       load_res = new_rd_Proj(dbgi, irg, block, load, mode_Iu, pn_ia32_Load_res);
+       ir_node  *load     = new_rd_ia32_Load(dbgi, irg, block, base, index, mem);
+       ir_node  *load_res = new_rd_Proj(dbgi, irg, block, load, mode_Iu, pn_ia32_Load_res);
 
        ia32_copy_am_attrs(load, node);
        if (is_ia32_is_reload(node))
                set_ia32_is_reload(load);
        set_irn_n(node, n_ia32_mem, new_NoMem());
 
-       switch (get_ia32_am_arity(node)) {
+       switch (get_ia32_am_support(node)) {
                case ia32_am_unary:
                        set_irn_n(node, n_ia32_unary_op, load_res);
                        break;
 
                case ia32_am_binary:
-                       if (is_ia32_Immediate(get_irn_n(node, n_ia32_Cmp_right))) {
-                               assert(is_ia32_Cmp(node)  || is_ia32_Cmp8Bit(node) ||
-                                      is_ia32_Test(node) || is_ia32_Test8Bit(node));
+                       if (is_ia32_Immediate(get_irn_n(node, n_ia32_binary_right))) {
                                set_irn_n(node, n_ia32_binary_left, load_res);
                        } else {
                                set_irn_n(node, n_ia32_binary_right, load_res);
                        }
                        break;
 
-               case ia32_am_ternary:
-                       set_irn_n(node, n_ia32_binary_right, load_res);
-                       break;
-
-               default: break;
+               default:
+                       panic("Unknown AM type");
        }
-       set_irn_n(node, n_ia32_base, noreg);
+       noreg = ia32_new_NoReg_gp(ia32_current_cg);
+       set_irn_n(node, n_ia32_base,  noreg);
        set_irn_n(node, n_ia32_index, noreg);
        set_ia32_am_offs_int(node, 0);
        set_ia32_am_sc(node, NULL);
@@ -1063,24 +1081,22 @@ static void turn_back_am(ir_node *node)
 
        /* rewire mem-proj */
        if (get_irn_mode(node) == mode_T) {
-               mem_proj = NULL;
+               const ir_edge_t *edge;
                foreach_out_edge(node, edge) {
                        ir_node *out = get_edge_src_irn(edge);
-                       if(get_irn_mode(out) == mode_M) {
-                               assert(mem_proj == NULL);
-                               mem_proj = out;
+                       if (get_irn_mode(out) == mode_M) {
+                               set_Proj_pred(out, load);
+                               set_Proj_proj(out, pn_ia32_Load_M);
+                               break;
                        }
                }
-
-               if(mem_proj != NULL) {
-                       set_Proj_pred(mem_proj, load);
-                       set_Proj_proj(mem_proj, pn_ia32_Load_M);
-               }
        }
 
        set_ia32_op_type(node, ia32_Normal);
        if (sched_is_scheduled(node))
                sched_add_before(node, load);
+
+       return load_res;
 }
 
 static ir_node *flags_remat(ir_node *node, ir_node *after)
@@ -1268,6 +1284,7 @@ static ir_node *create_push(ia32_code_gen_t *cg, ir_node *node, ir_node *schedpo
        set_ia32_use_frame(push);
        set_ia32_op_type(push, ia32_AddrModeS);
        set_ia32_ls_mode(push, mode_Is);
+       set_ia32_is_spill(push);
 
        sched_add_before(schedpoint, push);
        return push;
@@ -1286,6 +1303,7 @@ static ir_node *create_pop(ia32_code_gen_t *cg, ir_node *node, ir_node *schedpoi
        set_ia32_use_frame(pop);
        set_ia32_op_type(pop, ia32_AddrModeD);
        set_ia32_ls_mode(pop, mode_Is);
+       set_ia32_is_reload(pop);
 
        sched_add_before(schedpoint, pop);
 
@@ -1554,8 +1572,7 @@ static ir_node *ia32_get_pic_base(void *self) {
        get_eip     = new_rd_ia32_GetEIP(NULL, cg->irg, block);
        cg->get_eip = get_eip;
 
-       add_irn_dep(get_eip, get_irg_frame(cg->irg));
-
+       be_dep_on_frame(get_eip);
        return get_eip;
 }
 
@@ -1579,7 +1596,7 @@ static const arch_code_generator_if_t ia32_code_gen_if = {
  */
 static void *ia32_cg_init(be_irg_t *birg) {
        ia32_isa_t      *isa = (ia32_isa_t *)birg->main_env->arch_env;
-       ia32_code_gen_t *cg  = xcalloc(1, sizeof(*cg));
+       ia32_code_gen_t *cg  = XMALLOCZ(ia32_code_gen_t);
 
        cg->impl      = &ia32_code_gen_if;
        cg->irg       = birg->irg;
@@ -1741,7 +1758,7 @@ static arch_env_t *ia32_init(FILE *file_handle) {
 
        set_tarval_output_modes();
 
-       isa = xmalloc(sizeof(*isa));
+       isa = XMALLOC(ia32_isa_t);
        memcpy(isa, &ia32_isa_template, sizeof(*isa));
 
        if(mode_fpcw == NULL) {
@@ -1764,7 +1781,7 @@ static arch_env_t *ia32_init(FILE *file_handle) {
        ia32_build_8bit_reg_map_high(isa->regs_8bit_high);
 
 #ifndef NDEBUG
-       isa->name_obst = xmalloc(sizeof(*isa->name_obst));
+       isa->name_obst = XMALLOC(struct obstack);
        obstack_init(isa->name_obst);
 #endif /* NDEBUG */
 
@@ -1886,7 +1903,7 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type,
        call_flags.bits.store_args_sequential = 0;
        /* call_flags.bits.try_omit_fp                 not changed: can handle both settings */
        call_flags.bits.fp_free               = 0;  /* the frame pointer is fixed in IA32 */
-       call_flags.bits.call_has_imm          = 1;  /* No call immediates, we handle this by ourselves */
+       call_flags.bits.call_has_imm          = 0;  /* No call immediates, we handle this by ourselves */
 
        /* set parameter passing style */
        be_abi_call_set_flags(abi, call_flags, &ia32_abi_callbacks);
@@ -2085,16 +2102,13 @@ static const be_execution_unit_t ***ia32_get_allowed_execution_units(
 
        if (is_ia32_irn(irn)) {
                ret = get_ia32_exec_units(irn);
-       }
-       else if (is_be_node(irn)) {
-               if (be_is_Call(irn) || be_is_Return(irn)) {
+       } else if (is_be_node(irn)) {
+               if (be_is_Return(irn)) {
                        ret = _units_callret;
-               }
-               else if (be_is_Barrier(irn)) {
+               } else if (be_is_Barrier(irn)) {
                        ret = _units_dummy;
-               }
-               else {
-                        ret = _units_other;
+               } else {
+                       ret = _units_other;
                }
        }
        else {