This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

ifcvt: cond_exec-like behavior on cc0 machines


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]