added use extbb walker option
authorChristian Würdig <chriswue@ipd.info.uni-karlsruhe.de>
Mon, 20 Mar 2006 16:47:04 +0000 (16:47 +0000)
committerChristian Würdig <chriswue@ipd.info.uni-karlsruhe.de>
Mon, 20 Mar 2006 16:47:04 +0000 (16:47 +0000)
added lea->add transformation
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_map_regs.c
ir/be/ia32/ia32_new_nodes.c
ir/be/ia32/ia32_new_nodes.h
ir/be/ia32/ia32_nodes_attr.h
ir/be/ia32/ia32_transform.c
ir/be/ia32/ia32_transform.h

index 22ef49f..bd5cfd6 100644 (file)
@@ -469,6 +469,9 @@ static void ia32_finish_irg_walker(ir_node *irn, void *env) {
 
        /* check if there is a sub which need to be transformed */
        ia32_transform_sub_to_neg_add(irn, cg);
+
+       /* transform a LEA into an Add if possible */
+       ia32_transform_lea_to_add(irn, cg);
 }
 
 /**
@@ -688,6 +691,7 @@ static void *ia32_cg_init(FILE *F, const be_irg_t *birg) {
        cg->opt.doam      = 1;
        cg->opt.placecnst = 1;
        cg->opt.immops    = 1;
+       cg->opt.extbb     = 1;
 
 #ifndef NDEBUG
        if (isa->name_obst_size) {
index ee21946..142d3f8 100644 (file)
@@ -16,6 +16,7 @@ typedef struct _ia32_optimize_t {
        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 */
+       unsigned extbb     : 1;   /**< do extended basic block scheduling */
 } ia32_optimize_t;
 
 typedef struct _ia32_code_gen_t {
index 8010b5b..143ae0d 100644 (file)
@@ -44,8 +44,13 @@ extern int obstack_printf(struct obstack *obst, char *fmt, ...);
 
 #define SNPRINTF_BUF_LEN 128
 
+/* global arch_env for lc_printf functions */
 static const arch_env_t *arch_env = NULL;
 
+/* indicates whether blocks are scheduled or not
+   (this variable is set automatically) */
+static int have_block_sched       = 0;
+
 /*************************************************************
  *             _       _    __   _          _
  *            (_)     | |  / _| | |        | |
@@ -544,7 +549,6 @@ static char *get_cfop_target(const ir_node *irn, char *buf) {
        return buf;
 }
 
-static int have_block_sched = 0;
 /** Return the next block in Block schedule */
 static ir_node *next_blk_sched(const ir_node *block) {
        return have_block_sched ? get_irn_link(block) : NULL;
@@ -670,12 +674,7 @@ static void emit_ia32_TestJmp(const ir_node *irn, ia32_emit_env_t *env) {
        TestJmp_emitter(irn, env);
 }
 
-/**
- * Emits code for conditional test and jump with immediate.
- */
-static void emit_ia32_TestJmp_i(const ir_node *irn, ia32_emit_env_t *env) {
-       TestJmp_emitter(irn, env);
-}
+
 
 /*********************************************************
  *                 _ _       _
@@ -825,7 +824,7 @@ void emit_ia32_SwitchJmp(const ir_node *irn, ia32_emit_env_t *emit_env) {
                                        snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default case */");
                                        IA32_DO_EMIT;
                                }
-                               snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[i].target, buf), last_value);
+                               snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[i].target, buf));
                                snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */", last_value);
                                IA32_DO_EMIT;
                        }
@@ -1311,20 +1310,25 @@ void ia32_gen_routine(FILE *F, ir_graph *irg, const ia32_code_gen_t *cg) {
        ia32_emit_func_prolog(F, irg);
        irg_block_walk_graph(irg, ia32_gen_labels, NULL, &emit_env);
 
-#if 1
-       have_block_sched = 0;
-       irg_walk_blkwise_graph(irg, NULL, ia32_gen_block, &emit_env);
-#else
-       compute_extbb(irg);
+       if (cg->opt.extbb) {
+               /* schedule extended basic blocks */
 
-       list.start = NULL;
-       list.end   = NULL;
-       irg_extblock_walk_graph(irg, NULL, create_block_list, &list);
+               compute_extbb(irg);
 
-       have_block_sched = 1;
-       for (block = list.start; block; block = get_irn_link(block))
-               ia32_gen_block(block, &emit_env);
-#endif
+               list.start = NULL;
+               list.end   = NULL;
+               irg_extblock_walk_graph(irg, NULL, create_block_list, &list);
+
+               have_block_sched = 1;
+               for (block = list.start; block; block = get_irn_link(block))
+                       ia32_gen_block(block, &emit_env);
+       }
+       else {
+               /* "normal" block schedule */
+
+               have_block_sched = 0;
+               irg_walk_blkwise_graph(irg, NULL, ia32_gen_block, &emit_env);
+       }
 
        ia32_emit_func_epilog(F, irg);
 }
index e57ab2c..5950796 100644 (file)
@@ -255,14 +255,7 @@ long ia32_translate_proj_pos(const ir_node *proj) {
                        return 0;
                if (nr == pn_DivMod_res_mod)
                        return 1;
-
-               switch(get_ia32_flavour(pred)) {
-                       if (nr == pn_DivMod_res_div)
-                               return 0;
-                       if (nr == pn_DivMod_res_mod)
-                               return 1;
-                       assert(0 && "unsupported DivMod");
-               }
+               assert(0 && "unsupported DivMod");
        }
        else if (is_ia32_fDiv(pred)) {
                if (nr == pn_Quot_res)
index 59caaf0..e284860 100644 (file)
@@ -594,6 +594,14 @@ char *get_ia32_cnst(const ir_node *node) {
        return attr->cnst;
 }
 
+/**
+ * Sets the string representation of the internal const.
+ */
+void set_ia32_cnst(ir_node *node, char *cnst) {
+       ia32_attr_t *attr = get_ia32_attr(node);
+       attr->cnst = cnst;
+}
+
 /**
  * Sets the uses_frame flag.
  */
index 2a015ee..3e6e805 100644 (file)
@@ -114,6 +114,11 @@ void set_ia32_sc(ir_node *node, const char *sc);
  */
 char *get_ia32_cnst(const ir_node *node);
 
+/**
+ * Sets the string representation of the internal const.
+ */
+void set_ia32_cnst(ir_node *node, char *cnst);
+
 /**
  * Sets the uses_frame flag.
  */
index 336c7ec..6e7a502 100644 (file)
@@ -39,6 +39,7 @@ typedef enum {
        ia32_am_B    = ia32_B,
        ia32_am_I    = ia32_I,
        ia32_am_IS   = ia32_I | ia32_S,
+       ia32_am_BI   = ia32_B | ia32_I,
        ia32_am_OB   = ia32_O | ia32_B,
        ia32_am_OI   = ia32_O | ia32_I,
        ia32_am_OIS  = ia32_O | ia32_I | ia32_S,
index cb94555..017a968 100644 (file)
@@ -135,16 +135,11 @@ static const char *gen_fp_known_const(ir_mode *mode, ia32_known_const_t kct) {
  * Prints the old node name on cg obst and returns a pointer to it.
  */
 const char *get_old_node_name(ia32_transform_env_t *env) {
-       static int name_cnt = 0;
        ia32_isa_t *isa = (ia32_isa_t *)env->cg->arch_env->isa;
 
        lc_eoprintf(firm_get_arg_env(), isa->name_obst, "%+F", env->irn);
        obstack_1grow(isa->name_obst, 0);
        isa->name_obst_size += obstack_object_size(isa->name_obst);
-       name_cnt++;
-       if (name_cnt % 1024 == 0) {
-               printf("name obst size reached %d bytes after %d nodes\n", isa->name_obst_size, name_cnt);
-       }
        return obstack_finish(isa->name_obst);
 }
 #endif /* NDEBUG */
@@ -1727,6 +1722,120 @@ void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) {
        }
 }
 
+/**
+ * Transforms a LEA into an Add if possible
+ * THIS FUNCTIONS MUST BE CALLED AFTER REGISTER ALLOCATION.
+ */
+void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) {
+       ia32_am_flavour_t am_flav;
+       int               imm = 0;
+       ir_node          *res = NULL;
+       ir_node          *nomem, *noreg, *base, *index, *op1, *op2;
+       char             *offs;
+       ia32_transform_env_t tenv;
+       arch_register_t *out_reg, *base_reg, *index_reg;
+
+       /* must be a LEA */
+       if (! is_ia32_Lea(irn))
+               return;
+
+       am_flav = get_ia32_am_flavour(irn);
+
+       /* only some LEAs can be transformed to an Add */
+       if (am_flav != ia32_am_B && am_flav != ia32_am_OB && am_flav != ia32_am_OI && am_flav != ia32_am_BI)
+               return;
+
+       noreg = ia32_new_NoReg_gp(cg);
+       nomem = new_rd_NoMem(cg->irg);
+       op1   = noreg;
+       op2   = noreg;
+       base  = get_irn_n(irn, 0);
+       index = get_irn_n(irn,1);
+
+       offs  = get_ia32_am_offs(irn);
+
+       /* offset has a explicit sign -> we need to skip + */
+       if (offs && offs[0] == '+')
+               offs++;
+
+       out_reg   = arch_get_irn_register(cg->arch_env, irn);
+       base_reg  = arch_get_irn_register(cg->arch_env, base);
+       index_reg = arch_get_irn_register(cg->arch_env, index);
+
+       tenv.block = get_nodes_block(irn);
+       tenv.dbg   = get_irn_dbg_info(irn);
+       tenv.irg   = cg->irg;
+       tenv.irn   = irn;
+       tenv.mod   = cg->mod;
+       tenv.mode  = get_irn_mode(irn);
+       tenv.cg    = cg;
+
+       switch(get_ia32_am_flavour(irn)) {
+               case ia32_am_B:
+                       /* out register must be same as base register */
+                       if (! REGS_ARE_EQUAL(out_reg, base_reg))
+                               return;
+
+                       op1 = base;
+                       break;
+               case ia32_am_OB:
+                       /* out register must be same as base register */
+                       if (! REGS_ARE_EQUAL(out_reg, base_reg))
+                               return;
+
+                       op1 = base;
+                       imm = 1;
+                       break;
+               case ia32_am_OI:
+                       /* out register must be same as index register */
+                       if (! REGS_ARE_EQUAL(out_reg, index_reg))
+                               return;
+
+                       op1 = index;
+                       imm = 1;
+                       break;
+               case ia32_am_BI:
+                       /* out register must be same as one in register */
+                       if (REGS_ARE_EQUAL(out_reg, base_reg)) {
+                               op1 = base;
+                               op2 = index;
+                       }
+                       else if (REGS_ARE_EQUAL(out_reg, index_reg)) {
+                               op1 = index;
+                               op2 = base;
+                       }
+                       else {
+                               /* in registers a different from out -> no Add possible */
+                               return;
+                       }
+               default:
+                       break;
+       }
+
+       res = new_rd_ia32_Add(tenv.dbg, tenv.irg, tenv.block, noreg, noreg, op1, op2, nomem, mode_T);
+       arch_set_irn_register(cg->arch_env, res, out_reg);
+       set_ia32_op_type(res, ia32_Normal);
+
+       if (imm)
+               set_ia32_cnst(res, offs);
+
+       SET_IA32_ORIG_NODE(res, get_old_node_name(&tenv));
+
+       /* add Add to schedule */
+       sched_add_before(irn, res);
+
+       res = new_rd_Proj(tenv.dbg, tenv.irg, tenv.block, res, tenv.mode, 0);
+
+       /* add result Proj to schedule */
+       sched_add_before(irn, res);
+
+       /* remove the old LEA */
+       sched_remove(irn);
+
+       /* exchange the Add and the LEA */
+       exchange(irn, res);
+}
+
 /**
  * Transforms the given firm node (and maybe some other related nodes)
  * into one or more assembler nodes.
index b29291c..5c680b9 100644 (file)
@@ -12,4 +12,10 @@ void ia32_transform_node(ir_node *node, void *env);
  */
 void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg);
 
+/**
+ * Transforms a LEA into an Add if possible
+ * THIS FUNCTIONS MUST BE CALLED AFTER REGISTER ALLOCATION.
+ */
+void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg);
+
 #endif /* _IA32_TRANSFORM_H_ */