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]

[cond-optab] Fix doubleword shifts


This patch cures a failure in building libgcc on MMIX, Alpha and other
targets that lack a cbranchsi4 pattern (only cbranchdi4).

The reason of the problem is that I had overlooked that compare_from_rtx
can widen its operands.  This in retrospect is quite obvious; I missed
that because it only happens when expand (as opposed to if-conversion)
generates conditional moves: in particular this is the case with
doubleword shifts.

To fix this, I modified prepare_cmp_insn to use an optab_methods argument.
I also simplified the calling convention so that it plugs better in
functions that used to call compare_from_rtx.

Previously, the widening done by compare_from_rtx could in principle
leave partly formed sequences in the RTL stream, because compare_from_rtx
was not wrapped in start_sequence/end_sequence.  It probably never
happened, but I cleaned this up too.

Paolo

2009-03-26  Paolo Bonzini  <bonzini@gnu.org>

	* optabs.c (prepare_float_lib_cmp): Return an rtx and a machine mode.
	Accept other parameters by value.
	(prepare_cmp_insn): Return an rtx and a machine mode.  Accept
	other parameters by value.  Try to widen operands here based on
	an optab_methods argument.
	(emit_cmp_and_jump_insn_1): Remove widening loop.
	(emit_cmp_and_jump_insns): Adjust call to prepare_cmp_insn, remove
	obsolete assertion.
	(emit_conditional_move, emit_conditional_add, emit_conditional_trap):
	Use new prepare_cmp_insn.

Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	(branch cond-optab)
+++ gcc/optabs.c	(working copy)
@@ -94,8 +94,8 @@ enum insn_code movcc_gen_code[NUM_MACHIN
 enum insn_code vcond_gen_code[NUM_MACHINE_MODES];
 enum insn_code vcondu_gen_code[NUM_MACHINE_MODES];
 
-static void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *,
-				   enum machine_mode *, int *);
+static void prepare_float_lib_cmp (rtx, rtx, enum rtx_code, rtx *,
+				   enum machine_mode *);
 static rtx expand_unop_direct (enum machine_mode, optab, rtx, rtx, int);
 
 /* Debug facility for use in GDB.  */
@@ -3995,7 +3995,7 @@ can_compare_p (enum rtx_code code, enum 
 
    *PMODE is the mode of the inputs (in case they are const_int).
    *PUNSIGNEDP nonzero says that the operands are unsigned;
-   this matters if they need to be widened.
+   this matters if they need to be widened (as given by METHODS).
 
    If they have mode BLKmode, then SIZE specifies the size of both operands.
 
@@ -4008,14 +4008,18 @@ can_compare_p (enum rtx_code code, enum 
    comparisons must have already been folded.  */
 
 static void
-prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
-		  enum machine_mode *pmode, int *punsignedp,
-		  enum can_compare_purpose purpose)
+prepare_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
+		  int unsignedp, enum optab_methods methods,
+		  rtx *ptest, enum machine_mode *pmode)
 {
   enum machine_mode mode = *pmode;
-  rtx x = *px, y = *py;
-  int unsignedp = *punsignedp;
-  rtx libfunc;
+  rtx libfunc, test;
+  enum machine_mode cmp_mode;
+  enum mode_class mclass;
+
+  /* The other methods are not needed.  */
+  gcc_assert (methods == OPTAB_DIRECT || methods == OPTAB_WIDEN
+	      || methods == OPTAB_LIB_WIDEN);
 
 #ifdef HAVE_cc0
   /* Make sure if we have a canonical comparison.  The RTL
@@ -4032,7 +4036,7 @@ prepare_cmp_insn (rtx *px, rtx *py, enum
 
   if (mode == BLKmode)
     {
-      enum machine_mode cmp_mode, result_mode;
+      enum machine_mode result_mode;
       enum insn_code cmp_code;
       tree length_type;
       rtx libfunc;
@@ -4068,12 +4072,14 @@ prepare_cmp_insn (rtx *px, rtx *py, enum
 	  size = convert_to_mode (cmp_mode, size, 1);
 	  emit_insn (GEN_FCN (cmp_code) (result, x, y, size, opalign));
 
-	  *px = result;
-	  *py = const0_rtx;
-	  *pmode = result_mode;
+          *ptest = gen_rtx_fmt_ee (comparison, VOIDmode, result, const0_rtx);
+          *pmode = result_mode;
 	  return;
 	}
 
+      if (methods != OPTAB_LIB && methods != OPTAB_LIB_WIDEN)
+	goto fail;
+
       /* Otherwise call a library function, memcmp.  */
       libfunc = memcmp_libfunc;
       length_type = sizetype;
@@ -4087,8 +4093,8 @@ prepare_cmp_insn (rtx *px, rtx *py, enum
 					XEXP (x, 0), Pmode,
 					XEXP (y, 0), Pmode,
 					size, cmp_mode);
-      *px = result;
-      *py = const0_rtx;
+
+      *ptest = gen_rtx_fmt_ee (comparison, VOIDmode, result, const0_rtx);
       *pmode = result_mode;
       return;
     }
@@ -4103,15 +4109,43 @@ prepare_cmp_insn (rtx *px, rtx *py, enum
 	y = force_reg (mode, y);
     }
 
-  *px = x;
-  *py = y;
   if (GET_MODE_CLASS (mode) == MODE_CC)
     {
-      gcc_assert (can_compare_p (*pcomparison, CCmode, purpose));
+      gcc_assert (can_compare_p (comparison, CCmode, ccp_jump));
+      *ptest = gen_rtx_fmt_ee (comparison, VOIDmode, x, y);
       return;
     }
-  else if (can_compare_p (*pcomparison, mode, purpose))
-    return;
+
+  mclass = GET_MODE_CLASS (mode);
+  test = gen_rtx_fmt_ee (comparison, VOIDmode, x, y);
+  cmp_mode = mode;
+  do
+   {
+      enum insn_code icode;
+      icode = optab_handler (cbranch_optab, cmp_mode)->insn_code;
+      if (icode != CODE_FOR_nothing
+	  && insn_data[icode].operand[0].predicate (test, VOIDmode))
+	{
+	  x = prepare_operand (icode, x, 1, mode, cmp_mode, unsignedp);
+	  y = prepare_operand (icode, y, 2, mode, cmp_mode, unsignedp);
+	  if (x && y)
+	    {
+	      XEXP (test, 0) = x;
+	      XEXP (test, 1) = y;
+	      *ptest = test;
+	      *pmode = cmp_mode;
+	      return;
+	    }
+	}
+
+      if (methods == OPTAB_DIRECT || !CLASS_HAS_WIDER_MODES_P (mclass))
+	break;
+      cmp_mode = GET_MODE_WIDER_MODE (cmp_mode);
+    }
+  while (cmp_mode != VOIDmode);
+
+  if (methods != OPTAB_LIB_WIDEN)
+    goto fail;
 
   /* Handle a lib call just for the mode we are using.  */
   libfunc = optab_libfunc (cmp_optab, mode);
@@ -4140,22 +4174,28 @@ prepare_cmp_insn (rtx *px, rtx *py, enum
 	 case. For unsigned comparisons always compare against 1 after
 	 biasing the unbiased result by adding 1. This gives us a way to
 	 represent LTU. */
-      *px = result;
-      *pmode = word_mode;
-      *py = const1_rtx;
+      x = result;
+      y = const1_rtx;
 
       if (!TARGET_LIB_INT_CMP_BIASED)
 	{
-	  if (*punsignedp)
-	    *px = plus_constant (result, 1);  
+	  if (unsignedp)
+	    x = plus_constant (result, 1);  
 	  else
-	    *py = const0_rtx;
+	    y = const0_rtx;
 	}
+
+      *ptest = gen_rtx_fmt_ee (comparison, word_mode, x, y);
+      *pmode = word_mode;
       return;
     }
 
   gcc_assert (SCALAR_FLOAT_MODE_P (mode));
-  prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
+  prepare_float_lib_cmp (x, y, comparison, ptest, pmode);
+  return;
+
+ fail:
+  *ptest = NULL_RTX;
 }
 
 /* Before emitting an insn with code ICODE, make sure that X, which is going
@@ -4182,48 +4222,23 @@ prepare_operand (int icode, rtx x, int o
 }
 
 /* Subroutine of emit_cmp_and_jump_insns; this function is called when we know
-   we can do the comparison.
-   The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may
-   be NULL_RTX which indicates that only a comparison is to be generated.  */
+   we can do the branch.  */
 
 static void
-emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
-			  enum rtx_code comparison, int unsignedp, rtx label)
+emit_cmp_and_jump_insn_1 (rtx test, enum machine_mode mode, rtx label)
 {
-  rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
-  enum mode_class mclass = GET_MODE_CLASS (mode);
-  enum machine_mode wider_mode = mode;
-
-  do
-    {
-      enum machine_mode optab_mode = mclass == MODE_CC ? CCmode : wider_mode;
-      enum insn_code icode;
-      PUT_MODE (test, wider_mode);
-
-      icode = optab_handler (cbranch_optab, optab_mode)->insn_code;
-
-      if (icode != CODE_FOR_nothing
-	  && insn_data[icode].operand[0].predicate (test, wider_mode))
-	{
-	  x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp);
-	  y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp);
-
-	  /* Rebuild test so as to give freedom to the machine description
-	     whether to use operands[1]/operands[2] or not.  */
-	  test = gen_rtx_fmt_ee (comparison, VOIDmode, x, y); 
-	  gcc_assert (insn_data[icode].operand[0].predicate (test, VOIDmode));
-	  emit_jump_insn (GEN_FCN (icode) (test, x, y, label));
-	  return;
-	}
+  enum machine_mode optab_mode;
+  enum mode_class mclass;
+  enum insn_code icode;
 
-      if (!CLASS_HAS_WIDER_MODES_P (mclass))
-	break;
+  mclass = GET_MODE_CLASS (mode);
+  optab_mode = (mclass == MODE_CC) ? CCmode : mode;
+  icode = optab_handler (cbranch_optab, optab_mode)->insn_code;
 
-      wider_mode = GET_MODE_WIDER_MODE (wider_mode);
-    }
-  while (wider_mode != VOIDmode);
+  gcc_assert (icode != CODE_FOR_nothing);
+  gcc_assert (insn_data[icode].operand[0].predicate (test, VOIDmode));
 
-  gcc_unreachable ();
+  emit_jump_insn (GEN_FCN (icode) (test, XEXP (test, 0), XEXP (test, 1), label));
 }
 
 /* Generate code to compare X with Y so that the condition codes are
@@ -4248,16 +4263,11 @@ emit_cmp_and_jump_insns (rtx x, rtx y, e
 			 enum machine_mode mode, int unsignedp, rtx label)
 {
   rtx op0 = x, op1 = y;
+  rtx test;
 
   /* Swap operands and condition to ensure canonical RTL.  */
   if (swap_commutative_operands_p (x, y))
     {
-      /* If we're not emitting a branch, callers are required to pass
-	 operands in an order conforming to canonical RTL.  We relax this
-	 for commutative comparisons so callers using EQ don't need to do
-	 swapping by hand.  */
-      gcc_assert (label || (comparison == swap_condition (comparison)));
-
       op0 = y, op1 = x;
       comparison = swap_condition (comparison);
     }
@@ -4272,9 +4282,9 @@ emit_cmp_and_jump_insns (rtx x, rtx y, e
   if (unsignedp)
     comparison = unsigned_condition (comparison);
 
-  prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp,
-		    ccp_jump);
-  emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
+  prepare_cmp_insn (op0, op1, comparison, size, unsignedp, OPTAB_LIB_WIDEN,
+		    &test, &mode);
+  emit_cmp_and_jump_insn_1 (test, mode, label);
 }
 
 
@@ -4282,14 +4292,11 @@ emit_cmp_and_jump_insns (rtx x, rtx y, e
    COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  */
 
 static void
-prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
-		       enum machine_mode *pmode, int *punsignedp)
+prepare_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison,
+		       rtx *ptest, enum machine_mode *pmode)
 {
-  enum rtx_code comparison = *pcomparison;
   enum rtx_code swapped = swap_condition (comparison);
   enum rtx_code reversed = reverse_condition_maybe_unordered (comparison);
-  rtx x = *px;
-  rtx y = *py;
   enum machine_mode orig_mode = GET_MODE (x);
   enum machine_mode mode, cmp_mode;
   rtx value, target, insns, equiv;
@@ -4399,11 +4406,8 @@ prepare_float_lib_cmp (rtx *px, rtx *py,
       || FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
     comparison = reversed_p ? EQ : NE;
 
-  *px = target;
-  *py = const0_rtx;
+  *ptest = gen_rtx_fmt_ee (comparison, VOIDmode, target, const0_rtx);
   *pmode = cmp_mode;
-  *pcomparison = comparison;
-  *punsignedp = 0;
 }
 
 /* Generate code to indirectly jump to a location given in the rtx LOC.  */
@@ -4515,14 +4519,26 @@ emit_conditional_move (rtx target, enum 
     return NULL_RTX;
 
   do_pending_stack_adjust ();
-  insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
+  start_sequence ();
+  prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1),
+		    GET_CODE (comparison), NULL_RTX, false, OPTAB_WIDEN,
+		    &comparison, &cmode);
+  if (!comparison)
+    insn = NULL_RTX;
+  else
+    insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
 
   /* If that failed, then give up.  */
   if (insn == 0)
-    return 0;
+    {
+      end_sequence ();
+      return 0;
+    }
 
   emit_insn (insn);
-
+  insn = get_insns ();
+  end_sequence ();
+  emit_insn (insn);
   if (subtarget != target)
     convert_move (target, subtarget, 0);
 
@@ -4642,14 +4658,26 @@ emit_conditional_add (rtx target, enum r
     return NULL_RTX;
 
   do_pending_stack_adjust ();
-  insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
+  start_sequence ();
+  prepare_cmp_insn (XEXP (comparison, 0), XEXP (comparison, 1),
+                    GET_CODE (comparison), NULL_RTX, false, OPTAB_WIDEN,
+                    &comparison, &cmode);
+  if (!comparison)
+    insn = NULL_RTX;
+  else
+    insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
 
   /* If that failed, then give up.  */
   if (insn == 0)
-    return 0;
+    {
+      end_sequence ();
+      return 0;
+    }
 
   emit_insn (insn);
-
+  insn = get_insns ();
+  end_sequence ();
+  emit_insn (insn);
   if (subtarget != target)
     convert_move (target, subtarget, 0);
 
@@ -6653,18 +6681,26 @@ gen_cond_trap (enum rtx_code code, rtx o
   if (!insn_data[icode].operand[3].predicate (tcode, VOIDmode))
     return 0;
 
+  do_pending_stack_adjust ();
   start_sequence ();
-  op1 = prepare_operand (icode, op1, 1, mode, mode, 0);
-  op2 = prepare_operand (icode, op2, 2, mode, mode, 0);
-  if (!op1 || !op2)
+  prepare_cmp_insn (op1, op2, code, NULL_RTX, false, OPTAB_DIRECT,
+		    &trap_rtx, &mode);
+  if (!trap_rtx)
+    insn = NULL_RTX;
+  else
+    insn = GEN_FCN (icode) (trap_rtx, XEXP (trap_rtx, 0), XEXP (trap_rtx, 1),
+			    tcode);
+
+  /* If that failed, then give up.  */
+  if (insn == 0)
     {
       end_sequence ();
       return 0;
     }
-  trap_rtx = gen_rtx_fmt_ee (code, mode, op1, op2);
-  insn = GEN_FCN (icode) (trap_rtx, op1, op2, tcode);
-  end_sequence ();
 
+  emit_insn (insn);
+  insn = get_insns ();
+  end_sequence ();
   return insn;
 }
 


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