Author: zoltan
Date: 2007-11-21 11:52:58 -0500 (Wed, 21 Nov 2007)
New Revision: 90092
Modified:
branches/vargaz/mini-linear-il/mono/mono/mini/ChangeLog
branches/vargaz/mini-linear-il/mono/mono/mini/basic.cs
branches/vargaz/mini-linear-il/mono/mono/mini/local-propagation.c
branches/vargaz/mini-linear-il/mono/mono/mini/mini-codegen.c
branches/vargaz/mini-linear-il/mono/mono/mini/mini.c
branches/vargaz/mini-linear-il/mono/mono/mini/mini.h
Log:
2007-11-21 Zoltan Varga <[EMAIL PROTECTED]>
* local-propagation.c (mono_branch_to_cmov): Implement another form
of branch->cmov conversion.
* mini.c (mini_method_compile): Reorder order of optimizations a bit.
* mini.c: Export some bblock related functions.
* basic.cs: Add more branch->cmov tests.
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/ChangeLog
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/ChangeLog 2007-11-21
16:25:26 UTC (rev 90091)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/ChangeLog 2007-11-21
16:52:58 UTC (rev 90092)
@@ -1,5 +1,14 @@
2007-11-21 Zoltan Varga <[EMAIL PROTECTED]>
+ * local-propagation.c (mono_branch_to_cmov): Implement another form
+ of branch->cmov conversion.
+
+ * mini.c (mini_method_compile): Reorder order of optimizations a bit.
+
+ * mini.c: Export some bblock related functions.
+
+ * basic.cs: Add more branch->cmov tests.
+
* mini-ops.h: Add CMOV opcodes.
* cpu-amd64.md mini-amd64.c: Implement CMOV opcodes.
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/basic.cs
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/basic.cs 2007-11-21
16:25:26 UTC (rev 90091)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/basic.cs 2007-11-21
16:52:58 UTC (rev 90092)
@@ -1274,4 +1274,36 @@
return 0;
}
+
+ public static int cmov (int i) {
+ int j = 0;
+
+ if (i > 0)
+ j = 1;
+
+ return j;
+ }
+
+ public static int cmov2 (int i) {
+ int j = 0;
+
+ if (i <= 0)
+ ;
+ else
+ j = 1;
+
+ return j;
+ }
+
+ public static int test_0_branch_to_cmov_opt () {
+ if (cmov (0) != 0)
+ return 1;
+ if (cmov (1) != 1)
+ return 2;
+ if (cmov2 (0) != 0)
+ return 1;
+ if (cmov2 (1) != 1)
+ return 2;
+ return 0;
+ }
}
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/local-propagation.c
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/local-propagation.c
2007-11-21 16:25:26 UTC (rev 90091)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/local-propagation.c
2007-11-21 16:52:58 UTC (rev 90092)
@@ -1763,7 +1763,8 @@
/*
* This pass requires somewhat optimized IR code so it should be run
after
- * local cprop/deadce.
+ * local cprop/deadce. Also, it should be run before dominator
computation, since
+ * it changes control flow.
*/
for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
MonoBasicBlock *bb1, *bb2;
@@ -1931,17 +1932,163 @@
mono_unlink_bblock (cfg, bb, bb2);
mono_unlink_bblock (cfg, bb1, bb1->out_bb [0]);
mono_unlink_bblock (cfg, bb2, bb2->out_bb [0]);
+ mono_remove_bblock (cfg, bb1);
+ mono_remove_bblock (cfg, bb2);
- /* Merge bb1 and its successor if possible */
+ /* Merge bb and its successor if possible */
if ((bb->out_bb [0]->in_count == 1) && (bb->out_bb [0]
!= cfg->bb_exit) &&
(bb->region == bb->out_bb [0]->region)) {
// FIXME:
- //mono_merge_basic_blocks (bb, bb->out_bb [0]);
+ mono_merge_basic_blocks (bb, bb->out_bb [0]);
}
}
+
+ /* Look for the IR code generated from if (cond) <var> <- <a>
+ * which is:
+ * BB:
+ * b<cond> [BB1BB2]
+ * BB1:
+ * <var> <- <a>
+ * br BB2
+ */
+
+ if ((bb2->in_count == 1 && bb2->out_count == 1 && bb2->out_bb
[0] == bb1) ||
+ (bb1->in_count == 1 && bb1->out_count == 1 &&
bb1->out_bb [0] == bb2)) {
+ MonoInst *prev, *compare, *branch, *ins1, *cmov, *tmp;
+ gboolean simple;
+ int dreg, tmp_reg;
+ CompType comp_type;
+ CompRelation cond;
+ MonoBasicBlock *next_bb, *code_bb;
+
+ /* code_bb is the bblock containing code, next_bb is
the successor bblock */
+ if (bb2->in_count == 1 && bb2->out_count == 1 &&
bb2->out_bb [0] == bb1) {
+ code_bb = bb2;
+ next_bb = bb1;
+ } else {
+ code_bb = bb1;
+ next_bb = bb2;
+ }
+
+ ins1 = code_bb->code;
+
+ /* Check that code_bb is simple */
+ simple = TRUE;
+ for (tmp = ins1->next; tmp; tmp = tmp->next)
+ if (!((tmp->opcode == OP_NOP) || (tmp->opcode
== OP_BR)))
+ simple = FALSE;
+
+ if (!simple)
+ continue;
+
+ /* We move ins1 before the compare so it should have no
side effect */
+ if (!INS_HAS_NO_SIDE_EFFECT (ins1))
+ continue;
+
+ if (bb->last_ins && bb->last_ins->opcode == OP_BR_REG)
+ continue;
+
+ /* Find the compare instruction */
+ prev = NULL;
+ compare = bb->code;
+ g_assert (compare);
+ while (compare->next && !MONO_IS_COND_BRANCH_OP
(compare->next)) {
+ prev = compare;
+ compare = compare->next;
+ }
+ g_assert (compare->next && MONO_IS_COND_BRANCH_OP
(compare->next));
+ branch = compare->next;
+
+ /* Moving ins1 could change the comparison */
+ /* FIXME: */
+ if (!((compare->sreg1 != ins1->dreg) && (compare->sreg2
!= ins1->dreg)))
+ continue;
+
+ /* FIXME: */
+ comp_type = mono_opcode_to_type (branch->opcode,
compare->opcode);
+ if (!((comp_type == CMP_TYPE_I) || (comp_type ==
CMP_TYPE_L)))
+ continue;
+
+ /* FIXME: */
+ /* ins->type might not be set */
+ if (INS_INFO (ins1->opcode) [MONO_INST_DEST] != 'i')
+ continue;
+
+ /* FIXME: */
+ if (cfg->ret && ins1->dreg == cfg->ret->dreg)
+ continue;
+
+ if (cfg->verbose_level > 2) {
+ printf ("\tBranch -> CMove optimization (2) in
BB%d on\n", bb->block_num);
+ printf ("\t\t"); mono_print_ins (compare);
+ printf ("\t\t"); mono_print_ins (compare->next);
+ printf ("\t\t"); mono_print_ins (ins1);
+ }
+
+ changed = TRUE;
+
+ //printf ("HIT!\n");
+
+ tmp_reg = mono_alloc_dreg (cfg, STACK_I4);
+ dreg = ins1->dreg;
+
+ /* Rewrite ins1 to emit to tmp_reg */
+ ins1->dreg = tmp_reg;
+
+ /* Remove ins1 from code_bb */
+ code_bb->code = code_bb->last_ins = NULL;
+
+ /* Move ins1 before the comparison */
+ /* FIXME: Move this to a helper function */
+ if (prev == NULL) {
+ bb->code = ins1;
+ } else {
+ prev->next = ins1;
+ }
+ ins1->next = compare;
+
+ /* Add cmov instruction */
+ MONO_INST_NEW (cfg, cmov, OP_NOP);
+ cmov->dreg = dreg;
+ cmov->sreg1 = dreg;
+ cmov->sreg2 = tmp_reg;
+ cond = mono_opcode_to_cond (branch->opcode);
+ if (code_bb == bb2)
+ cond = mono_negate_cond (cond);
+ switch (mono_opcode_to_type (branch->opcode,
compare->opcode)) {
+ case CMP_TYPE_I:
+ cmov->opcode = int_cmov_opcodes [cond];
+ break;
+ case CMP_TYPE_L:
+ cmov->opcode = long_cmov_opcodes [cond];
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ compare->next = cmov;
+ cmov->next = branch;
+
+ /* Rewrite the branch */
+ branch->opcode = OP_BR;
+ branch->inst_target_bb = next_bb;
+ mono_link_bblock (cfg, bb, branch->inst_target_bb);
+
+ /* Reorder bblocks */
+ mono_unlink_bblock (cfg, bb, code_bb);
+ mono_unlink_bblock (cfg, code_bb, next_bb);
+
+ /* Merge bb and its successor if possible */
+ if ((bb->out_bb [0]->in_count == 1) && (bb->out_bb [0]
!= cfg->bb_exit) &&
+ (bb->region == bb->out_bb [0]->region)) {
+ mono_merge_basic_blocks (bb, bb->out_bb [0]);
+ }
+ }
}
- if (changed)
+ if (changed) {
+ if (cfg->opt & MONO_OPT_BRANCH)
+ mono_optimize_branches (cfg);
/* Merging bblocks could make some variables local */
mono_handle_global_vregs (cfg);
+ }
}
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/mini-codegen.c
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/mini-codegen.c
2007-11-21 16:25:26 UTC (rev 90091)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/mini-codegen.c
2007-11-21 16:52:58 UTC (rev 90092)
@@ -2020,6 +2020,35 @@
}
}
+CompRelation
+mono_negate_cond (CompRelation cond)
+{
+ switch (cond) {
+ case CMP_EQ:
+ return CMP_NE;
+ case CMP_NE:
+ return CMP_EQ;
+ case CMP_LE:
+ return CMP_GT;
+ case CMP_GE:
+ return CMP_LT;
+ case CMP_LT:
+ return CMP_GE;
+ case CMP_GT:
+ return CMP_LE;
+ case CMP_LE_UN:
+ return CMP_GT_UN;
+ case CMP_GE_UN:
+ return CMP_LT_UN;
+ case CMP_LT_UN:
+ return CMP_GE_UN;
+ case CMP_GT_UN:
+ return CMP_LE_UN;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
CompType
mono_opcode_to_type (int opcode, int cmp_opcode)
{
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/mini.c
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/mini.c 2007-11-21
16:25:26 UTC (rev 90091)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/mini.c 2007-11-21
16:52:58 UTC (rev 90092)
@@ -10802,6 +10802,23 @@
}
}
+/*
+ * mono_remove_block:
+ *
+ * Remove BB from the control flow graph
+ */
+void
+mono_remove_bblock (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+ MonoBasicBlock *tmp_bb;
+
+ for (tmp_bb = cfg->bb_entry; tmp_bb && tmp_bb->next_bb != bb; tmp_bb =
tmp_bb->next_bb)
+ ;
+
+ g_assert (tmp_bb);
+ tmp_bb->next_bb = bb->next_bb;
+}
+
/* checks that a and b represent the same instructions, conservatively,
* it can return FALSE also for two trees that are equal.
* FIXME: also make sure there are no side effects.
@@ -10909,8 +10926,8 @@
* Optimizes the branches on the Control Flow Graph
*
*/
-static void
-optimize_branches (MonoCompile *cfg)
+void
+mono_optimize_branches (MonoCompile *cfg)
{
int i, changed = FALSE;
MonoBasicBlock *bb, *bbn;
@@ -11871,12 +11888,19 @@
}
if (cfg->opt & MONO_OPT_BRANCH)
- optimize_branches (cfg);
+ mono_optimize_branches (cfg);
if (cfg->opt & MONO_OPT_SSAPRE) {
remove_critical_edges (cfg);
}
+ if (cfg->new_ir) {
+ /* This must be done _before_ global reg alloc and _after_
decompose */
+ mono_handle_global_vregs (cfg);
+ mono_local_deadce (cfg);
+ mono_branch_to_cmov (cfg);
+ }
+
/* Depth-first ordering on basic blocks */
cfg->bblocks = mono_mempool_alloc (cfg->mempool, sizeof
(MonoBasicBlock*) * (cfg->num_bblocks + 1));
@@ -11913,14 +11937,6 @@
mono_compute_natural_loops (cfg);
}
-
- if (cfg->new_ir) {
- /* This must be done _before_ global reg alloc and _after_
decompose */
- mono_handle_global_vregs (cfg);
- mono_local_deadce (cfg);
- mono_branch_to_cmov (cfg);
- }
-
/* after method_to_ir */
if (parts == 1)
return cfg;
@@ -12013,7 +12029,7 @@
mono_ssa_remove (cfg);
if (cfg->opt & MONO_OPT_BRANCH)
- optimize_branches (cfg);
+ mono_optimize_branches (cfg);
}
#endif
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/mini.h
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/mini.h 2007-11-21
16:25:26 UTC (rev 90091)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/mini.h 2007-11-21
16:52:58 UTC (rev 90092)
@@ -1013,7 +1013,9 @@
guint32 mono_alloc_dreg (MonoCompile *cfg, MonoStackType
stack_type) MONO_INTERNAL;
void mono_link_bblock (MonoCompile *cfg, MonoBasicBlock
*from, MonoBasicBlock* to) MONO_INTERNAL;
void mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock
*from, MonoBasicBlock* to) MONO_INTERNAL;
+void mono_remove_bblock (MonoCompile *cfg, MonoBasicBlock
*bb) MONO_INTERNAL;
void mono_merge_basic_blocks (MonoBasicBlock *bb,
MonoBasicBlock *bbn) MONO_INTERNAL;
+void mono_optimize_branches (MonoCompile *cfg) MONO_INTERNAL;
void mono_blockset_print (MonoCompile *cfg, MonoBitSet
*set, const char *name, guint idom) MONO_INTERNAL;
void mono_print_tree (MonoInst *tree) MONO_INTERNAL;
void mono_print_tree_nl (MonoInst *tree) MONO_INTERNAL;
@@ -1142,6 +1144,7 @@
void mini_emit_memcpy2 (MonoCompile *cfg, int destreg, int
doffset, int srcreg, int soffset, int size, int align) MONO_INTERNAL;
CompRelation mono_opcode_to_cond (int opcode) MONO_INTERNAL;
CompType mono_opcode_to_type (int opcode, int cmp_opcode)
MONO_INTERNAL;
+CompRelation mono_negate_cond (CompRelation cond) MONO_INTERNAL;
void mono_decompose_long_opts (MonoCompile *cfg) MONO_INTERNAL;
void mono_decompose_vtype_opts (MonoCompile *cfg) MONO_INTERNAL;
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches