fixed frame entity handling in am optimizer
authorChristian Würdig <chriswue@ipd.info.uni-karlsruhe.de>
Fri, 10 Mar 2006 15:01:48 +0000 (15:01 +0000)
committerChristian Würdig <chriswue@ipd.info.uni-karlsruhe.de>
Fri, 10 Mar 2006 15:01:48 +0000 (15:01 +0000)
fixed some bugs

ir/be/ia32/bearch_ia32.c
ir/be/ia32/bearch_ia32_t.h
ir/be/ia32/ia32_emitter.c
ir/be/ia32/ia32_optimize.c
ir/be/ia32/ia32_spec.pl
ir/be/ia32/ia32_transform.c

index 8a0cab0..87c6d43 100644 (file)
@@ -213,7 +213,7 @@ static void ia32_set_stack_bias(const void *self, ir_node *irn, int bias) {
        char buf[64];
        const ia32_irn_ops_t *ops = self;
 
-       if (is_ia32_use_frame(irn)) {
+       if (is_ia32_use_frame(irn) && bias != 0) {
                ia32_am_flavour_t am_flav = get_ia32_am_flavour(irn);
 
                DBG((ops->cg->mod, LEVEL_1, "stack biased %+F with %d\n", irn, bias));
@@ -265,8 +265,11 @@ static void ia32_prepare_graph(void *self) {
        dump_ir_block_graph_sched(cg->irg, "-transformed");
        edges_deactivate(cg->irg);
        edges_activate(cg->irg);
-       irg_walk_blkwise_graph(cg->irg, NULL, ia32_optimize_am, cg);
-       dump_ir_block_graph_sched(cg->irg, "-am");
+
+       if (cg->opt.doam) {
+               irg_walk_blkwise_graph(cg->irg, NULL, ia32_optimize_am, cg);
+               dump_ir_block_graph_sched(cg->irg, "-am");
+       }
 }
 
 
@@ -528,6 +531,12 @@ static void *ia32_cg_init(FILE *F, const be_irg_t *birg) {
        cg->tv_ent   = pmap_create();
        cg->birg     = birg;
 
+       /* set optimizations */
+       cg->opt.incdec    = 0;
+       cg->opt.doam      = 1;
+       cg->opt.placecnst = 1;
+       cg->opt.immops    = 1;
+
        isa->num_codegens++;
 
        if (isa->num_codegens > 1)
@@ -660,7 +669,7 @@ void ia32_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *ab
        int       i, ignore;
        ir_mode **modes;
        const arch_register_t *reg;
-       be_abi_call_flags_t call_flags = { 0, 0, 0, 0, 1 };
+       be_abi_call_flags_t call_flags = { 0, 0, 1, 0, 1 };
 
        /* get the between type and the frame pointer save entity */
        between_type = get_between_type();
index 1ff141a..5cf21fa 100644 (file)
@@ -8,6 +8,13 @@
 
 /* some typedefs */
 
+typedef struct _ia32_optimize_t {
+       unsigned incdec    : 1;   /**< optimize add/sub 1/-1 to inc/dec */
+       unsigned doam      : 1;   /**< do address mode optimizations */
+       unsigned placecnst : 1;   /**< place constants in the blocks where they are used */
+       unsigned immops    : 1;   /**< create operations with immediates */
+} ia32_optimize_t;
+
 typedef struct _ia32_code_gen_t {
        const arch_code_generator_if_t *impl;          /**< implementation */
        ir_graph                       *irg;           /**< current irg */
@@ -19,6 +26,7 @@ typedef struct _ia32_code_gen_t {
        pmap                           *types;         /**< A map of modes to primitive types */
        pmap                           *tv_ent;        /**< A map of entities that store tarvals */
        const be_irg_t                 *birg;          /**< The be-irg (contains additional information about the irg) */
+       ia32_optimize_t                 opt;           /**< contains optimization information */
 } ia32_code_gen_t;
 
 typedef struct _ia32_isa_t {
index f24e922..13302d5 100644 (file)
@@ -234,22 +234,6 @@ static const arch_register_t *get_out_reg(const ir_node *irn, int pos) {
        return reg;
 }
 
-/**
- * Returns the number of the in register at position pos.
- */
-int get_ia32_reg_nr(ir_node *irn, int pos, int in_out) {
-       const arch_register_t *reg;
-
-       if (in_out == 1) {
-               reg = get_in_reg(irn, pos);
-       }
-       else {
-               reg = get_out_reg(irn, pos);
-       }
-
-       return arch_register_get_index(reg);
-}
-
 enum io_direction {
   IN_REG,
   OUT_REG
@@ -266,7 +250,7 @@ static const char *get_ia32_reg_name(ir_node *irn, int pos, enum io_direction in
        }
        else {
                /* destination address mode nodes don't have outputs */
-               if (get_ia32_op_type(irn) == ia32_AddrModeD) {
+               if (is_ia32_irn(irn) && get_ia32_op_type(irn) == ia32_AddrModeD) {
                        return "MEM";
                }
 
@@ -786,6 +770,23 @@ void emit_be_IncSP(const ir_node *irn, emit_env_t *emit_env) {
        }
 }
 
+void emit_be_SetSP(const ir_node *irn, emit_env_t *emit_env) {
+       FILE *F = emit_env->out;
+
+       lc_efprintf(ia32_get_arg_env(), F, "\tmov %1D,%3S\t\t\t/* restore SP */\n", irn, irn);
+}
+
+void emit_be_Copy(const ir_node *irn, emit_env_t *emit_env) {
+       FILE *F = emit_env->out;
+
+       lc_efprintf(ia32_get_arg_env(), F, "\tmov %1D,%1S\t\t\t/* %+F */\n", irn, irn, irn);
+}
+
+void emit_be_Perm(const ir_node *irn, emit_env_t *emit_env) {
+       FILE *F = emit_env->out;
+
+       lc_efprintf(ia32_get_arg_env(), F, "\txchg %1S, %2S\t\t\t/* %+F(%1A, %2A) */\n", irn, irn, irn);
+}
 
 /***********************************************************************************
  *                  _          __                                             _
@@ -822,6 +823,9 @@ static void ia32_register_emitters(void) {
        /* benode emitter */
        BE_EMIT(Call);
        BE_EMIT(IncSP);
+       BE_EMIT(SetSP);
+       BE_EMIT(Copy);
+       BE_EMIT(Perm);
 
        /* firm emitter */
        EMIT(Jmp);
index 376b327..a0a9c5c 100644 (file)
@@ -193,6 +193,11 @@ void ia32_place_consts(ir_node *irn, void *env) {
                        tenv.block = get_Block_cfgpred_block(get_nodes_block(irn), i);
                }
 
+               /* put the const into the block where the original const was */
+               if (! cg->opt.placecnst) {
+                       tenv.block = get_nodes_block(pred);
+               }
+
                switch (opc) {
                        case iro_Const:
                                cnst = gen_Const(&tenv);
@@ -316,6 +321,62 @@ static int pred_is_specific_nodeblock(const ir_node *bl, const ir_node *pred,
        return 0;
 }
 
+/**
+ * Checks if irn is a candidate for address calculation or address mode.
+ *
+ * address calculation (AC):
+ * - none of the operand must be a Load  within the same block OR
+ * - all Loads must have more than one user                    OR
+ * - the irn has a frame entity (it's a former FrameAddr)
+ *
+ * address mode (AM):
+ * - at least one operand has to be a Load within the same block AND
+ * - the load must not have other users than the irn             AND
+ * - the irn must not have a frame entity set
+ *
+ * @param block       The block the Loads must/not be in
+ * @param irn         The irn to check
+ * @param check_addr  1 if to check for address calculation, 0 otherwise
+ * return 1 if irn is a candidate for AC or AM, 0 otherwise
+ */
+static int is_candidate(const ir_node *block, const ir_node *irn, int check_addr) {
+       ir_node *load_proj;
+       int      n, is_cand = check_addr;
+
+       if (pred_is_specific_nodeblock(block, get_irn_n(irn, 2), is_ia32_Load)) {
+               load_proj = get_irn_n(irn, 2);
+               n         = ia32_get_irn_n_edges(load_proj);
+               is_cand   = check_addr ? (n == 1 ? 0 : is_cand) : (n == 1 ? 1 : is_cand);
+       }
+
+       if (pred_is_specific_nodeblock(block, get_irn_n(irn, 3), is_ia32_Load)) {
+               load_proj = get_irn_n(irn, 3);
+               n         = ia32_get_irn_n_edges(load_proj);
+               is_cand   = check_addr ? (n == 1 ? 0 : is_cand) : (n == 1 ? 1 : is_cand);
+       }
+
+       is_cand = get_ia32_frame_ent(irn) ? (check_addr ? 1 : 0) : (check_addr ? 0 : 1);
+
+       return is_cand;
+}
+
+/**
+ * Compares the base and index addr and the load/store entities
+ * and returns 1 if they are equal.
+ */
+static int load_store_addr_is_equal(const ir_node *load, const ir_node *store,
+                                                                       const ir_node *addr_b, const ir_node *addr_i)
+{
+       int     is_equal = (addr_b == get_irn_n(load, 0)) && (addr_i == get_irn_n(load, 1));
+       entity *lent     = get_ia32_frame_ent(load);
+       entity *sent     = get_ia32_frame_ent(store);
+
+       /* are both entities set and equal? */
+       is_equal = (lent && sent && (lent == sent)) ? 1 : is_equal;
+
+       return is_equal;
+}
+
 /**
  * Folds Add or Sub to LEA if possible
  */
@@ -451,7 +512,9 @@ static ir_node *fold_addr(be_abi_irg_t *babi, ir_node *irn, firm_dbg_module_t *m
                /* If we have an Add with a real right operand (not NoReg) and  */
                /* the LEA contains already an index calculation then we create */
                /* a new LEA.                                                   */
-               if (isadd && !be_is_NoReg(babi, index) && (am_flav & ia32_am_I)) {
+               /* If the LEA contains already a frame_entity then we also      */
+               /* create a new one  otherwise we would loose it.               */
+               if (isadd && ((!be_is_NoReg(babi, index) && (am_flav & ia32_am_I)) || get_ia32_frame_ent(left))) {
                        DBG((mod, LEVEL_1, "\tleave old LEA, creating new one\n"));
                }
                else {
@@ -495,6 +558,13 @@ static ir_node *fold_addr(be_abi_irg_t *babi, ir_node *irn, firm_dbg_module_t *m
                        }
                }
 
+               /* copy the frame entity (could be set in case of Add */
+               /* which was a FrameAddr) */
+               set_ia32_frame_ent(res, get_ia32_frame_ent(irn));
+
+               if (is_ia32_use_frame(irn))
+                       set_ia32_use_frame(res);
+
                /* set scale */
                set_ia32_am_scale(res, scale);
 
@@ -574,9 +644,8 @@ void ia32_optimize_am(ir_node *irn, void *env) {
                right = get_irn_n(irn, 3);
 
            /* Do not try to create a LEA if one of the operands is a Load. */
-               if (! pred_is_specific_nodeblock(block, left,  is_ia32_Load)  &&
-                       ! pred_is_specific_nodeblock(block, right, is_ia32_Load))
-               {
+               /* check is irn is a candidate for address calculation */
+               if (is_candidate(block, irn, 1)) {
                        res = fold_addr(babi, irn, mod, noreg_gp);
                }
        }
@@ -615,10 +684,8 @@ void ia32_optimize_am(ir_node *irn, void *env) {
                                set_irn_n(irn, 1, get_irn_n(left, 1));
                        }
                }
-               /* check if at least one operand is a Load */
-               else if (pred_is_specific_nodeblock(block, get_irn_n(irn, 2), is_ia32_Ld) ||
-                                pred_is_specific_nodeblock(block, get_irn_n(irn, 3), is_ia32_Ld))
-               {
+               /* check if the node is an address mode candidate */
+               else if (is_candidate(block, irn, 0)) {
                        left  = get_irn_n(irn, 2);
                        if (get_irn_arity(irn) == 4) {
                                /* it's an "unary" operation */
@@ -711,8 +778,7 @@ void ia32_optimize_am(ir_node *irn, void *env) {
                                        load = get_Proj_pred(right);
 
                                        /* Compare Load and Store address */
-                                       if ((addr_b == get_irn_n(load, 0)) && (addr_i == get_irn_n(load, 1)))
-                                       {
+                                       if (load_store_addr_is_equal(load, store, addr_b, addr_i)) {
                                                /* Right Load is from same address, so we can */
                                                /* disconnect the Load and Store here        */
 
@@ -723,6 +789,11 @@ void ia32_optimize_am(ir_node *irn, void *env) {
                                                set_ia32_am_scale(irn, get_ia32_am_scale(load));
                                                set_ia32_am_flavour(irn, get_ia32_am_flavour(load));
                                                set_ia32_op_type(irn, ia32_AddrModeD);
+                                               set_ia32_frame_ent(irn, get_ia32_frame_ent(load));
+                                               set_ia32_ls_mode(irn, get_ia32_ls_mode(load));
+
+                                               if (is_ia32_use_frame(load))
+                                                       set_ia32_use_frame(irn);
 
                                                /* connect to Load memory and disconnect Load */
                                                if (get_irn_arity(irn) == 5) {
@@ -786,6 +857,11 @@ void ia32_optimize_am(ir_node *irn, void *env) {
                                set_ia32_am_scale(irn, get_ia32_am_scale(left));
                                set_ia32_am_flavour(irn, get_ia32_am_flavour(left));
                                set_ia32_op_type(irn, ia32_AddrModeS);
+                               set_ia32_frame_ent(irn, get_ia32_frame_ent(left));
+                               set_ia32_ls_mode(irn, get_ia32_ls_mode(left));
+
+                               if (is_ia32_use_frame(left))
+                                       set_ia32_use_frame(irn);
 
                                /* connect to Load memory */
                                if (get_irn_arity(irn) == 5) {
index c325933..f791806 100644 (file)
@@ -360,7 +360,14 @@ $arch = "ia32";
   "comment"   => "represents an integer constant",
   "cmp_attr"  => "  return ia32_compare_immop_attr(attr_a, attr_b);\n",
   "reg_req"   => { "out" => [ "gp" ] },
-  "emit"      => '. mov %D1, %C\t\t\t/* Mov Const into register */',
+  "emit"      =>
+'  if (get_ia32_Immop_tarval(n) == get_tarval_null(get_irn_mode(n))) {
+4.   sub %D1, %D1\t\t\t/* optimized mov 0 to register */
+  }
+  else {
+4.   mov %D1, %C\t\t\t/* Mov Const into register */
+  }
+',
 },
 
 "Cdq" => {
index a56b879..994b020 100644 (file)
@@ -183,8 +183,13 @@ static ir_node *gen_binop(ia32_transform_env_t *env, ir_node *op1, ir_node *op2,
        ir_node           *expr_op, *imm_op;
 
 
-       /* check if it's an operation with immediate */
-       if (is_op_commutative(get_irn_op(env->irn))) {
+       /* Check if immediate optimization is on and */
+       /* if it's an operation with immediate.      */
+       if (! env->cg->opt.immops) {
+               expr_op = op1;
+               imm_op  = NULL;
+       }
+       else if (is_op_commutative(get_irn_op(env->irn))) {
                imm_op  = get_immediate_op(op1, op2);
                expr_op = get_expr_op(op1, op2);
        }
@@ -263,7 +268,9 @@ static ir_node *gen_shift_binop(ia32_transform_env_t *env, ir_node *op1, ir_node
 
        assert(! mode_is_float(mode) && "Shift/Rotate with float not supported");
 
-       imm_op  = get_immediate_op(NULL, op2);
+       /* Check if immediate optimization is on and */
+       /* if it's an operation with immediate.      */
+       imm_op  = env->cg->opt.immops ? get_immediate_op(NULL, op2) : NULL;
        expr_op = get_expr_op(op1, op2);
 
        assert((expr_op || imm_op) && "invalid operands");
@@ -357,8 +364,8 @@ static ir_node *gen_imm_Add(ia32_transform_env_t *env, ir_node *expr_op, ir_node
        int                     normal_add = 1;
        tarval_classification_t class_tv, class_negtv;
 
-       /* const_op: tarval or SymConst? */
-       if (tv) {
+       /* try to optimize to inc/dec  */
+       if (env->cg->opt.incdec && tv) {
                /* optimize tarvals */
                class_tv    = classify_tarval(tv);
                class_negtv = classify_tarval(tarval_neg(tv));
@@ -403,7 +410,9 @@ static ir_node *gen_Add(ia32_transform_env_t *env, ir_node *op1, ir_node *op2) {
        ir_node  *nomem  = new_NoMem();
        ir_node  *expr_op, *imm_op;
 
-       imm_op  = get_immediate_op(op1, op2);
+       /* Check if immediate optimization is on and */
+       /* if it's an operation with immediate.      */
+       imm_op  = env->cg->opt.immops ? get_immediate_op(op1, op2) : NULL;
        expr_op = get_expr_op(op1, op2);
 
        assert((expr_op || imm_op) && "invalid operands");
@@ -643,8 +652,8 @@ static ir_node *gen_imm_Sub(ia32_transform_env_t *env, ir_node *expr_op, ir_node
        int                     normal_sub = 1;
        tarval_classification_t class_tv, class_negtv;
 
-       /* const_op: tarval or SymConst? */
-       if (tv) {
+       /* try to optimize to inc/dec  */
+       if (env->cg->opt.incdec && tv) {
                /* optimize tarvals */
                class_tv    = classify_tarval(tv);
                class_negtv = classify_tarval(tarval_neg(tv));
@@ -687,7 +696,9 @@ static ir_node *gen_Sub(ia32_transform_env_t *env, ir_node *op1, ir_node *op2) {
        ir_node  *nomem  = new_NoMem();
        ir_node  *expr_op, *imm_op;
 
-       imm_op  = get_immediate_op(NULL, op2);
+       /* Check if immediate optimization is on and */
+       /* if it's an operation with immediate.      */
+       imm_op  = env->cg->opt.immops ? get_immediate_op(NULL, op2) : NULL;
        expr_op = get_expr_op(op1, op2);
 
        assert((expr_op || imm_op) && "invalid operands");
@@ -1201,7 +1212,7 @@ static ir_node *gen_Cond(ia32_transform_env_t *env) {
                cmp_b = get_Cmp_right(pred);
 
                /* check if we can use a CondJmp with immediate */
-               cnst = get_immediate_op(cmp_a, cmp_b);
+               cnst = env->cg->opt.immops ? get_immediate_op(cmp_a, cmp_b) : NULL;
                expr = get_expr_op(cmp_a, cmp_b);
 
                if (cnst && expr) {
@@ -1247,7 +1258,7 @@ static ir_node *gen_CopyB(ia32_transform_env_t *env) {
 
        /* If we have to copy more than 16 bytes, we use REP MOVSx and */
        /* then we need the size explicitly in ECX.                    */
-       if (size >= 16) {
+       if (size >= 16 * 4) {
                rem = size & 0x3; /* size % 4 */
                size >>= 2;
 
@@ -1275,7 +1286,7 @@ static ir_node *gen_CopyB(ia32_transform_env_t *env) {
  * @return The transformed node.
  */
 static ir_node *gen_Mux(ia32_transform_env_t *env) {
-       ir_node  *node  = env->irn;
+       ir_node *node  = env->irn;
 
        return new_rd_ia32_CMov(env->dbg, env->irg, env->block,
                get_Mux_sel(node), get_Mux_false(node), get_Mux_true(node), env->mode);
@@ -1293,19 +1304,28 @@ static ir_node *gen_Mux(ia32_transform_env_t *env) {
  *
  ********************************************/
 
-static ir_node *gen_FrameAddr(ia32_transform_env_t *tenv) {
+static ir_node *gen_FrameAddr(ia32_transform_env_t *env) {
        ir_node *new_op = NULL;
+       ir_node *node   = env->irn;
+       ir_node *op     = get_irn_n(node, 0);
+       ir_node *noreg  = ia32_new_NoReg_gp(env->cg);
+       ir_node *nomem  = new_rd_NoMem(env->irg);
 
-       return new_op;
+       new_op = new_rd_ia32_Add(env->dbg, env->irg, env->block, noreg, noreg, op, noreg, nomem, mode_T);
+       set_ia32_frame_ent(new_op, be_get_frame_entity(node));
+       set_ia32_am_support(new_op, ia32_am_Full);
+       set_ia32_use_frame(new_op);
+
+       return new_rd_Proj(env->dbg, env->irg, env->block, new_op, env->mode, 0);
 }
 
-static ir_node *gen_FrameLoad(ia32_transform_env_t *tenv) {
+static ir_node *gen_FrameLoad(ia32_transform_env_t *env) {
        ir_node *new_op = NULL;
 
        return new_op;
 }
 
-static ir_node *gen_FrameStore(ia32_transform_env_t *tenv) {
+static ir_node *gen_FrameStore(ia32_transform_env_t *env) {
        ir_node *new_op = NULL;
 
        return new_op;