This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
ifcvt: cond_exec-like behavior on cc0 machines
- From: Alexandre Oliva <aoliva at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: 17 Jul 2003 15:40:47 -0300
- Subject: ifcvt: cond_exec-like behavior on cc0 machines
- Organization: GCC Team, Red Hat
I found out cond_exec can't contain cc0 in the condition, so I had to
change my plans in regards to implementing conditional bit-set and
bit-clear instructions on the port I'm working on. It turned out
that, since the port is an extension to an existing port that uses cc0
pervasively, I decided converting the port to represent all condition
codes explicitly wasn't worth it, and it would be a pain, as most
instructions touch them.
I tried several alternatives using if_then_else, but neither combine
nor ifcvt could figure out how to take advantage of them. I ended up
extending ifcvt such that it tries to sets protected by a branch into
conditional sets, or even actual if_then_else sets. This patch has
enabled me to define patterns like this:
(define_insn "*condbset"
[(set (match_operand:QI 0 "" "")
(if_then_else:QI
(match_operator:QI 2 "eqne_operator"
[(cc0) (const_int 0)])
(ior:QI
(match_operand:QI 3 "" "0")
(match_operand:QI 1 "" ""))
(match_dup 3)))]
and have ifcvt generate them.
This patch has passed bootstrap on athlon-pc-linux-gnu. It was also
tested on the port I'm working on. Ok to install?
Index: gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* genconfig.c (have_condop_flag): New.
(walk_insn_part): Set it.
(main): Define HAVE_conditional_operations.
* ifcvt.c (HAVE_conditional_operations): Define.
(struct noce_if_info): Add else_bb and orig_x.
(noce_try_cond_op): New.
(noce_process_if_block): Call it. Set else_bb and orig_x in
if_info. Cope with changes in if_info.x.
Index: gcc/genconfig.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/genconfig.c,v
retrieving revision 1.50
diff -u -p -r1.50 genconfig.c
--- gcc/genconfig.c 1 Jun 2003 15:59:08 -0000 1.50
+++ gcc/genconfig.c 17 Jul 2003 06:40:08 -0000
@@ -36,6 +36,7 @@ static int max_dup_operands; /* Large
static int max_clobbers_per_insn;
static int have_cc0_flag;
static int have_cmove_flag;
+static int have_condop_flag;
static int have_cond_exec_flag;
static int have_lo_sum_flag;
static int have_peephole_flag;
@@ -135,6 +136,8 @@ walk_insn_part (rtx part, int recog_p, i
&& GET_CODE (XEXP (part, 1)) == MATCH_OPERAND
&& GET_CODE (XEXP (part, 2)) == MATCH_OPERAND)
have_cmove_flag = 1;
+ else if (recog_p && non_pc_set_src)
+ have_condop_flag = 1;
break;
case COND_EXEC:
@@ -341,6 +344,9 @@ main (int argc, char **argv)
if (have_cmove_flag)
printf ("#define HAVE_conditional_move 1\n");
+
+ if (have_condop_flag)
+ printf ("#define HAVE_conditional_operations 1\n");
if (have_cond_exec_flag)
printf ("#define HAVE_conditional_execution 1\n");
Index: gcc/ifcvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ifcvt.c,v
retrieving revision 1.122
diff -u -p -r1.122 ifcvt.c
--- gcc/ifcvt.c 6 Jul 2003 06:15:35 -0000 1.122
+++ gcc/ifcvt.c 17 Jul 2003 18:02:21 -0000
@@ -46,6 +46,9 @@
#ifndef HAVE_conditional_move
#define HAVE_conditional_move 0
#endif
+#ifndef HAVE_conditional_operations
+#define HAVE_conditional_operations 0
+#endif
#ifndef HAVE_incscc
#define HAVE_incscc 0
#endif
@@ -564,10 +567,11 @@ cond_exec_process_if_block (ce_if_block_
struct noce_if_info
{
- basic_block test_bb;
+ basic_block test_bb, else_bb;
rtx insn_a, insn_b;
rtx x, a, b;
rtx jump, cond, cond_earliest;
+ rtx orig_x;
};
static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
@@ -575,6 +579,7 @@ static int noce_try_store_flag (struct n
static int noce_try_addcc (struct noce_if_info *);
static int noce_try_store_flag_constants (struct noce_if_info *);
static int noce_try_store_flag_mask (struct noce_if_info *);
+static int noce_try_cond_op (struct noce_if_info *);
static rtx noce_emit_cmove (struct noce_if_info *, rtx, enum rtx_code, rtx,
rtx, rtx, rtx);
static int noce_try_cmove (struct noce_if_info *);
@@ -988,6 +993,63 @@ noce_try_store_flag_mask (struct noce_if
return FALSE;
}
+/* Convert "if (test) x = a;" to "x = (test) ? a : x;". If x is set
+ to b before, try both "? a : b" and "? a : x". */
+
+static int
+noce_try_cond_op (struct noce_if_info *if_info)
+{
+ rtx set;
+
+ if (! if_info->else_bb
+ && (set = single_set (if_info->insn_a))
+ && SET_DEST (set) == if_info->orig_x
+ && SET_SRC (set) == if_info->a)
+ {
+ rtx cond_expr = SET_SRC (single_set (if_info->jump));
+ enum rtx_code cond_code = GET_CODE (XEXP (cond_expr, 0));
+ enum machine_mode jump_mode = GET_MODE (cond_expr);
+ rtx jump_true = XEXP (cond_expr, 1);
+ rtx jump_false = XEXP (cond_expr, 2);
+
+ /* Reuse the condition of the jump. */
+ PUT_CODE (XEXP (cond_expr, 0),
+ reversed_comparison_code (XEXP (cond_expr, 0), if_info->jump));
+ PUT_MODE (cond_expr, GET_MODE (if_info->orig_x));
+ XEXP (cond_expr, 1) = if_info->a;
+ XEXP (cond_expr, 2) = if_info->b;
+ if (validate_change (if_info->insn_a, &SET_SRC (set), cond_expr, 0))
+ goto success;
+
+ XEXP (cond_expr, 2) = if_info->orig_x;
+
+ if (validate_change (if_info->insn_a, &SET_SRC (set), cond_expr, 0))
+ goto success;
+
+ /* If the transformation fails, restore the jump. */
+ PUT_CODE (XEXP (cond_expr, 0), cond_code);
+ PUT_MODE (cond_expr, jump_mode);
+ XEXP (cond_expr, 1) = jump_true;
+ XEXP (cond_expr, 2) = jump_false;
+ return FALSE;
+
+ success:
+ /* If it works, we'll delete the original insns, so create a new
+ insn while still sharing most rtl. */
+ start_sequence ();
+ set = emit_insn (PATTERN (if_info->insn_a));
+ end_sequence ();
+ emit_insn_before_setloc (set, if_info->jump,
+ INSN_LOCATOR (if_info->insn_a));
+
+ /* Don't store x in orig_x, we're already storing in it. */
+ if_info->x = if_info->orig_x;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/* Helper function for noce_try_cmove and noce_try_cmove_arith. */
static rtx
@@ -1819,6 +1881,7 @@ noce_process_if_block (struct ce_if_bloc
/* Set up the info block for our subroutines. */
if_info.test_bb = test_bb;
+ if_info.else_bb = else_bb;
if_info.cond = cond;
if_info.jump = jump;
if_info.insn_a = insn_a;
@@ -1826,6 +1889,7 @@ noce_process_if_block (struct ce_if_bloc
if_info.x = x;
if_info.a = a;
if_info.b = b;
+ if_info.orig_x = orig_x;
/* Try optimizations in some approximation of a useful order. */
/* ??? Should first look to see if X is live incoming at all. If it
@@ -1859,7 +1923,7 @@ noce_process_if_block (struct ce_if_bloc
else if (insn_b && side_effects_p (orig_x))
return FALSE;
- x = orig_x;
+ if_info.x = orig_x;
goto success;
}
@@ -1869,6 +1933,9 @@ noce_process_if_block (struct ce_if_bloc
goto success;
if (noce_try_abs (&if_info))
goto success;
+ if (HAVE_conditional_operations
+ && noce_try_cond_op (&if_info))
+ goto success;
if (HAVE_conditional_move
&& noce_try_cmove (&if_info))
goto success;
@@ -1906,10 +1973,10 @@ noce_process_if_block (struct ce_if_bloc
delete_insn (jump);
/* If we used a temporary, fix it up now. */
- if (orig_x != x)
+ if (if_info.x != orig_x)
{
start_sequence ();
- noce_emit_move_insn (copy_rtx (orig_x), x);
+ noce_emit_move_insn (copy_rtx (orig_x), if_info.x);
insn_b = get_insns ();
end_sequence ();
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist Professional serial bug killer