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]

cr logical insn implementation for rs6000



This patch represents the CR logical operations for rs6000
in RTL, explains them (well, somewhat) to the scheduler,
and changes the branch-emitting logic and sCOND-emitting logic to use
them.

There are still a few pieces to do:
- Remove the %D output_operand modifier
- Update the call architecture to use the new insns
- Perhaps even try to make combine use the new insns
  to reduce the number of branches.

I hope even this much is a significant improvement.

I'll commit it when the bootstrap completes on powerpc-linux.

-- 
- Geoffrey Keating <geoffk@cygnus.com>

===File ~/patches/cygnus/rs6000-emitbranch.patch============
2000-09-05  Geoff Keating  <geoffk@cygnus.com>

	* config/rs6000/rs6000.c (validate_condition_mode): New function.
	(branch_comparison_operator): Call validate_condition_mode to
	abort rather than returning 0.
	(branch_positive_comparison_operator): New function.
	(scc_comparison_operator): Call validate_condition_mode to abort
	rather than returning 0.
	(ccr_bit): Call validate_condition_mode.  Update for
	new branch scheme.
	(print_operand): Delete %C modifier.  Update %E case
	to use EQ bit not SO bit.
	(rs6000_reverse_condition): New function.
	(rs6000_generate_compare): New function.
	(rs6000_emit_sCOND): New function.
	(rs6000_emit_cbranch): New function.
	(output_cbranch): The length of a long branch insn is
	now only 8 bytes.  Add validate_condition_mode.  Use
	rs6000_reverse_condition.  Remove cror generation.
	* config/rs6000/rs6000.h: Update comments.
	(PREDICATE_CODES): Add new predicate.  Update codes used
	by branch_comparison_operator and scc_comparison_operator.
	* config/rs6000/rs6000-protos.h: Add prototypes for
	new external functions.
	* config/rs6000/rs6000.md: Add new scheduling parameters
	for cr_logical instructions.  Change length of branch
	instructions.
	(bCOND patterns): Call rs6000_emit_cbranch.
	(sCOND patterns): Call rs6000_emit_sCOND.
	(branch patterns): Change lengths to 4.
	(cr logical patterns): New.

Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.10
diff -p -u -u -p -r1.10 rs6000-protos.h
--- rs6000-protos.h	2000/08/13 21:49:36	1.10
+++ rs6000-protos.h	2000/09/06 05:53:29
@@ -73,6 +73,8 @@ extern int expand_block_move PARAMS ((rt
 extern int load_multiple_operation PARAMS ((rtx, enum machine_mode));
 extern int store_multiple_operation PARAMS ((rtx, enum machine_mode));
 extern int branch_comparison_operator PARAMS ((rtx, enum machine_mode));
+extern int branch_positive_comparison_operator 
+  PARAMS ((rtx, enum machine_mode));
 extern int scc_comparison_operator PARAMS ((rtx, enum machine_mode));
 extern int trap_comparison_operator PARAMS ((rtx, enum machine_mode));
 extern int boolean_operator PARAMS ((rtx, enum machine_mode));
@@ -87,6 +89,10 @@ extern enum reg_class secondary_reload_c
 extern int ccr_bit PARAMS ((rtx, int));
 extern void print_operand PARAMS ((FILE *, rtx, int));
 extern void print_operand_address PARAMS ((FILE *, rtx));
+extern enum rtx_code rs6000_reverse_condition PARAMS ((enum machine_mode,
+						       enum rtx_code));
+extern void rs6000_emit_sCOND PARAMS ((enum rtx_code, rtx));
+extern void rs6000_emit_cbranch PARAMS ((enum rtx_code, rtx));
 extern char * output_cbranch PARAMS ((rtx, const char *, int, rtx));
 extern void output_toc PARAMS ((FILE *, rtx, int, enum machine_mode));
 extern int rs6000_adjust_cost PARAMS ((rtx, rtx, rtx, int));
Index: gcc/config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.146
diff -p -u -u -p -r1.146 rs6000.c
--- rs6000.c	2000/08/24 20:31:35	1.146
+++ rs6000.c	2000/09/06 05:53:32
@@ -119,6 +119,9 @@ static int rs6000_sr_alias_set;
 static void rs6000_add_gc_roots PARAMS ((void));
 static int num_insns_constant_wide PARAMS ((HOST_WIDE_INT));
 static rtx expand_block_move_mem PARAMS ((enum machine_mode, rtx, rtx));
+static void validate_condition_mode 
+  PARAMS ((enum rtx_code, enum machine_mode));
+static rtx rs6000_generate_compare PARAMS ((enum rtx_code));
 static void rs6000_maybe_dead PARAMS ((rtx));
 static void rs6000_emit_stack_tie PARAMS ((void));
 static void rs6000_frame_related PARAMS ((rtx, rtx, HOST_WIDE_INT, rtx, rtx));
@@ -3212,6 +3215,48 @@ stmw_operation (op, mode)
   return 1;
 }
 
+
+/* A validation routine:  say whether CODE, a condition code,
+   and MODE match.  The other alternatives either don't make
+   sense or should never be generated.  */
+static void
+validate_condition_mode (code, mode)
+     enum rtx_code code;
+     enum machine_mode mode;
+{
+  if (GET_RTX_CLASS (code) != '<' 
+      || GET_MODE_CLASS (mode) != MODE_CC)
+    abort ();
+
+  /* These don't make sense.  */
+  if ((code == GT || code == LT || code == GE || code == LE)
+      && mode == CCUNSmode)
+    abort ();
+
+  if ((code == GTU || code == LTU || code == GEU || code == LEU)
+      && mode != CCUNSmode)
+    abort ();
+
+  if (mode != CCFPmode
+      && (code == ORDERED || code == UNORDERED
+	  || code == UNEQ || code == LTGT
+	  || code == UNGT || code == UNLT
+	  || code == UNGE || code == UNLE))
+    abort();
+  
+  /* These should never be generated.  */
+  if (mode == CCFPmode
+      && (code == LE || code == GE
+	  || code == UNEQ || code == LTGT
+	  || code == UNGT || code == UNLT))
+    abort ();
+
+  /* These are invalid; the information is not there.  */
+  if (mode == CCEQmode 
+      && code != EQ && code != NE)
+    abort ();
+}
+
 /* Return 1 if OP is a comparison operation that is valid for a branch insn.
    We only check the opcode against the mode of the CC value here.  */
 
@@ -3230,17 +3275,32 @@ branch_comparison_operator (op, mode)
   if (GET_MODE_CLASS (cc_mode) != MODE_CC)
     return 0;
 
-  if ((code == GT || code == LT || code == GE || code == LE)
-      && cc_mode == CCUNSmode)
-    return 0;
+  validate_condition_mode (code, cc_mode);
 
-  if ((code == GTU || code == LTU || code == GEU || code == LEU)
-      && (cc_mode != CCUNSmode))
+  return 1;
+}
+
+/* Return 1 if OP is a comparison operation that is valid for a branch
+   insn and which is true if the corresponding bit in the CC register
+   is set.  */
+
+int
+branch_positive_comparison_operator (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  enum rtx_code code;
+
+  if (! branch_comparison_operator (op, mode))
     return 0;
 
-  return 1;
+  code = GET_CODE (op);
+  return (code == EQ || code == LT || code == GT
+	  || code == LTU || code == GTU
+	  || code == UNORDERED);
 }
 
+
 /* Return 1 if OP is a comparison operation that is valid for an scc insn.
    We check the opcode against the mode of the CC value and disallow EQ or
    NE comparisons for integers.  */
@@ -3263,18 +3323,9 @@ scc_comparison_operator (op, mode)
   if (GET_MODE_CLASS (cc_mode) != MODE_CC)
     return 0;
 
-  if (code == NE && cc_mode != CCFPmode)
-    return 0;
+  validate_condition_mode (code, cc_mode);
 
-  if ((code == GT || code == LT || code == GE || code == LE)
-      && cc_mode == CCUNSmode)
-    return 0;
-
-  if ((code == GTU || code == LTU || code == GEU || code == LEU)
-      && (cc_mode != CCUNSmode))
-    return 0;
-
-  if (cc_mode == CCEQmode && code != EQ && code != NE)
+  if (code == NE && cc_mode != CCFPmode)
     return 0;
 
   return 1;
@@ -3287,8 +3338,7 @@ trap_comparison_operator (op, mode)
 {
   if (mode != VOIDmode && mode != GET_MODE (op))
     return 0;
-  return (GET_RTX_CLASS (GET_CODE (op)) == '<'
-          || GET_CODE (op) == EQ || GET_CODE (op) == NE);
+  return GET_RTX_CLASS (GET_CODE (op)) == '<';
 }
 
 int
@@ -3538,12 +3588,8 @@ ccr_bit (op, scc_p)
   cc_regnum = REGNO (reg);
   base_bit = 4 * (cc_regnum - CR0_REGNO);
 
-  /* In CCEQmode cases we have made sure that the result is always in the
-     third bit of the CR field.  */
+  validate_condition_mode (code, cc_mode);
 
-  if (cc_mode == CCEQmode)
-    return base_bit + 3;
-
   switch (code)
     {
     case NE:
@@ -3558,16 +3604,13 @@ ccr_bit (op, scc_p)
       return base_bit + 3;
 
     case GE:  case GEU:
-      /* If floating-point, we will have done a cror to put the bit in the
+      /* If scc, we will have done a cror to put the bit in the
 	 unordered position.  So test that bit.  For integer, this is ! LT
 	 unless this is an scc insn.  */
-      return cc_mode == CCFPmode || scc_p ? base_bit + 3 : base_bit;
+      return scc_p ? base_bit + 3 : base_bit;
 
     case LE:  case LEU:
-      return cc_mode == CCFPmode || scc_p ? base_bit + 3 : base_bit + 1;
-
-    case UNEQ: case UNGT: case UNLT: case LTGT:
-      return base_bit + 3;
+      return scc_p ? base_bit + 3 : base_bit + 1;
 
     default:
       abort ();
@@ -3710,40 +3753,11 @@ print_operand (file, x, code)
       /* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise
 	 output_operand.  */
 
-    case 'C':
-      {
-	enum rtx_code code = GET_CODE (x);
-	
-	/* This is an optional cror needed for certain floating-point
-	   comparisons.  Otherwise write nothing.  */
-	if ((code == LE || code == GE
-	     || code == UNEQ || code == LTGT
-	     || code == UNGT || code == UNLT)
-	    && GET_MODE (XEXP (x, 0)) == CCFPmode)
-	  {
-	    int base_bit = 4 * (REGNO (XEXP (x, 0)) - CR0_REGNO);
-	    int bit0, bit1;
-	    
-	    if (code == UNEQ)
-	      bit0 = 2;
-	    else if (code == UNGT || code == GE)
-	      bit0 = 1;
-	    else
-	      bit0 = 0;
-	    if (code == LTGT)
-	      bit1 = 1;
-	    else if (code == LE || code == GE)
-	      bit1 = 2;
-	    else
-	      bit1 = 3;
-	    
-	    fprintf (file, "cror %d,%d,%d\n\t", base_bit + 3,
-		     base_bit + bit1, base_bit + bit0);
-	  }
-      }
-      return;
-
     case 'D':
+      /* There used to be a comment for 'C' reading "This is an
+	   optional cror needed for certain floating-point
+	   comparisons.  Otherwise write nothing."  */
+
       /* Similar, except that this is for an scc, so we must be able to
 	 encode the test in a single bit that is one.  We do the above
 	 for any LE, GE, GEU, or LEU and invert the bit for NE.  */
@@ -3767,11 +3781,11 @@ print_operand (file, x, code)
       return;
 
     case 'E':
-      /* X is a CR register.  Print the number of the third bit of the CR */
+      /* X is a CR register.  Print the number of the EQ bit of the CR */
       if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
 	output_operand_lossage ("invalid %%E value");
       else
-	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 3);
+	fprintf (file, "%d", 4 * (REGNO (x) - CR0_REGNO) + 2);
       return;
 
     case 'f':
@@ -4013,7 +4027,9 @@ print_operand (file, x, code)
     case 'q':
       /* This outputs the logical code corresponding to a boolean
 	 expression.  The expression may have one or both operands
-	 negated (if one, only the first one).  */
+	 negated (if one, only the first one).  For condition register
+         logical operations, it will also treat the negated
+         CR codes as NOTs, but not handle NOTs of them.  */
       {
 	const char *const *t = 0;
 	const char *s;
@@ -4420,6 +4436,129 @@ print_operand_address (file, x)
     abort ();
 }
 
+enum rtx_code
+rs6000_reverse_condition (mode, code)
+     enum machine_mode mode;
+     enum rtx_code code;
+{
+  /* Reversal of FP compares takes care -- an ordered compare
+     becomes an unordered compare and vice versa.  */
+  if (mode == CCFPmode)
+    code = reverse_condition_maybe_unordered (code);
+  else
+    code = reverse_condition (code);
+}
+
+
+/* Generate a compare for CODE.  Return a brand-new rtx that
+   represents the result of the compare.  */
+static rtx
+rs6000_generate_compare (code)
+     enum rtx_code code;
+{
+  enum machine_mode comp_mode;
+  rtx compare_result;
+
+  if (rs6000_compare_fp_p)
+    comp_mode = CCFPmode;
+  else if (code == GTU || code == LTU
+	  || code == GEU || code == LEU)
+    comp_mode = CCUNSmode;
+  else
+    comp_mode = CCmode;
+
+  /* First, the compare.  */
+  compare_result = gen_reg_rtx (comp_mode);
+  emit_insn (gen_rtx_SET (VOIDmode, compare_result,
+			  gen_rtx_COMPARE (comp_mode,
+					   rs6000_compare_op0, 
+					   rs6000_compare_op1)));
+  
+  /* Some kinds of FP comparisons need an OR operation.  */
+  if (rs6000_compare_fp_p
+      && (code == LE || code == GE
+	  || code == UNEQ || code == LTGT
+	  || code == UNGT || code == UNLT))
+    {
+      enum rtx_code or1, or2;
+      rtx or1_rtx, or2_rtx, compare2_rtx;
+      rtx or_result = gen_reg_rtx (CCEQmode);
+      
+      switch (code)
+	{
+	case LE: or1 = LT;  or2 = EQ;  break;
+	case GE: or1 = GT;  or2 = EQ;  break;
+	case UNEQ: or1 = UNORDERED;  or2 = EQ;  break;
+	case LTGT: or1 = LT;  or2 = GT;  break;
+	case UNGT: or1 = UNORDERED;  or2 = GT;  break;
+	case UNLT: or1 = UNORDERED;  or2 = LT;  break;
+	default:  abort ();
+	}
+      validate_condition_mode (or1, comp_mode);
+      validate_condition_mode (or2, comp_mode);
+      or1_rtx = gen_rtx (or1, SImode, compare_result, const0_rtx);
+      or2_rtx = gen_rtx (or2, SImode, compare_result, const0_rtx);
+      compare2_rtx = gen_rtx_COMPARE (CCEQmode,
+				      gen_rtx_IOR (SImode, or1_rtx, or2_rtx),
+				      const_true_rtx);
+      emit_insn (gen_rtx_SET (VOIDmode, or_result, compare2_rtx));
+
+      compare_result = or_result;
+      code = EQ;
+    }
+
+  validate_condition_mode (code, GET_MODE (compare_result));
+  
+  return gen_rtx (code, VOIDmode, compare_result, const0_rtx);
+}
+
+
+/* Emit the RTL for an sCOND pattern.  */
+
+void
+rs6000_emit_sCOND (code, result)
+     enum rtx_code code;
+     rtx result;
+{
+  rtx condition_rtx;
+  enum machine_mode op_mode;
+
+  condition_rtx = rs6000_generate_compare (code);
+
+  op_mode = GET_MODE (rs6000_compare_op0);
+  if (op_mode == VOIDmode)
+    op_mode = GET_MODE (rs6000_compare_op1);
+
+  if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
+    {
+      PUT_MODE (condition_rtx, DImode);
+      convert_move (result, condition_rtx, 0);
+    }
+  else
+    {
+      PUT_MODE (condition_rtx, SImode);
+      emit_insn (gen_rtx_SET (VOIDmode, result, condition_rtx));
+    }
+}
+
+
+/* Emit a branch of kind CODE to location LOC.  */
+
+void
+rs6000_emit_cbranch (code, loc)
+     enum rtx_code code;
+     rtx loc;
+{
+  rtx condition_rtx, loc_ref;
+
+  condition_rtx = rs6000_generate_compare (code);
+  loc_ref = gen_rtx_LABEL_REF (VOIDmode, loc);
+  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
+			       gen_rtx_IF_THEN_ELSE (VOIDmode, condition_rtx,
+						     loc_ref, pc_rtx)));
+}
+
+
 /* Return the string to output a conditional branch to LABEL, which is
    the operand number of the label, or -1 if the branch is really a
    conditional return.  
@@ -4444,52 +4583,22 @@ output_cbranch (op, label, reversed, ins
   rtx cc_reg = XEXP (op, 0);
   enum machine_mode mode = GET_MODE (cc_reg);
   int cc_regno = REGNO (cc_reg) - CR0_REGNO;
-  int need_longbranch = label != NULL && get_attr_length (insn) == 12;
+  int need_longbranch = label != NULL && get_attr_length (insn) == 8;
   int really_reversed = reversed ^ need_longbranch;
   char *s = string;
   const char *ccode;
   const char *pred;
   rtx note;
 
-  /* Work out which way this really branches.  */
+  validate_condition_mode (code, mode);
+
+  /* Work out which way this really branches.  We could use
+     reverse_condition_maybe_unordered here always but this
+     makes the resulting assembler clearer.  */
   if (really_reversed)
-    {
-      /* Reversal of FP compares takes care -- an ordered compare
-	 becomes an unordered compare and vice versa.  */
-      if (mode == CCFPmode)
-	code = reverse_condition_maybe_unordered (code);
-      else
-	code = reverse_condition (code);
-    }
+    code = rs6000_reverse_condition (mode, code);
 
-  /* If needed, print the CROR required for various floating-point
-     comparisons; and decide on the condition code to test.  */
-  if ((code == LE || code == GE
-       || code == UNEQ || code == LTGT
-       || code == UNGT || code == UNLT)
-      && mode == CCFPmode)
-    {
-      int base_bit = 4 * cc_regno;
-      int bit0, bit1;
-      
-      if (code == UNEQ)
-	bit0 = 2;
-      else if (code == UNGT || code == GE)
-	bit0 = 1;
-      else
-	bit0 = 0;
-      if (code == LTGT)
-	bit1 = 1;
-      else if (code == LE || code == GE)
-	bit1 = 2;
-      else
-	bit1 = 3;
-      
-      s += sprintf (s, "cror %d,%d,%d\n\t", base_bit + 3,
-		    base_bit + bit1, base_bit + bit0);
-      ccode = "so";
-    }
-  else switch (code)
+  switch (code)
     {
       /* Not all of these are actually distinct opcodes, but
 	 we distinguish them for clarity of the resulting assembler.  */
Index: gcc/config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.91
diff -p -u -u -p -r1.91 rs6000.h
--- rs6000.h	2000/09/04 01:42:27	1.91
+++ rs6000.h	2000/09/06 05:53:35
@@ -2275,18 +2275,19 @@ do {									     \
    For the RS/6000, we need separate modes when unsigned (logical) comparisons
    are being done and we need a separate mode for floating-point.  We also
    use a mode for the case when we are comparing the results of two
-   comparisons.  */
+   comparisons, as then only the EQ bit is valid in the register.  */
 
 #define EXTRA_CC_MODES		\
     CC(CCUNSmode,  "CCUNS")	\
     CC(CCFPmode,   "CCFP")	\
     CC(CCEQmode,   "CCEQ")
 
-/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
-   return the mode to be used for the comparison.  For floating-point, CCFPmode
-   should be used.  CCUNSmode should be used for unsigned comparisons.
-   CCEQmode should be used when we are doing an inequality comparison on
-   the result of a comparison. CCmode should be used in all other cases.  */
+/* Given a comparison code (EQ, NE, etc.) and the first operand of a
+   COMPARE, return the mode to be used for the comparison.  For
+   floating-point, CCFPmode should be used.  CCUNSmode should be used
+   for unsigned comparisons.  CCEQmode should be used when we are
+   doing an inequality comparison on the result of a
+   comparison.  CCmode should be used in all other cases.  */
 
 #define SELECT_CC_MODE(OP,X,Y) \
   (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? CCFPmode	\
@@ -2720,54 +2721,57 @@ do {									\
 
 /* Define the codes that are matched by predicates in rs6000.c.  */
 
-#define PREDICATE_CODES						\
-  {"short_cint_operand", {CONST_INT}},				\
-  {"u_short_cint_operand", {CONST_INT}},			\
-  {"non_short_cint_operand", {CONST_INT}},			\
-  {"gpc_reg_operand", {SUBREG, REG}},				\
-  {"cc_reg_operand", {SUBREG, REG}},				\
-  {"cc_reg_not_cr0_operand", {SUBREG, REG}},			\
-  {"reg_or_short_operand", {SUBREG, REG, CONST_INT}}, 		\
-  {"reg_or_neg_short_operand", {SUBREG, REG, CONST_INT}},	\
-  {"reg_or_u_short_operand", {SUBREG, REG, CONST_INT}}, 	\
-  {"reg_or_cint_operand", {SUBREG, REG, CONST_INT}}, 		\
-  {"reg_or_arith_cint_operand", {SUBREG, REG, CONST_INT}}, 	\
+#define PREDICATE_CODES							   \
+  {"short_cint_operand", {CONST_INT}},					   \
+  {"u_short_cint_operand", {CONST_INT}},				   \
+  {"non_short_cint_operand", {CONST_INT}},				   \
+  {"gpc_reg_operand", {SUBREG, REG}},					   \
+  {"cc_reg_operand", {SUBREG, REG}},					   \
+  {"cc_reg_not_cr0_operand", {SUBREG, REG}},				   \
+  {"reg_or_short_operand", {SUBREG, REG, CONST_INT}},			   \
+  {"reg_or_neg_short_operand", {SUBREG, REG, CONST_INT}},		   \
+  {"reg_or_u_short_operand", {SUBREG, REG, CONST_INT}},			   \
+  {"reg_or_cint_operand", {SUBREG, REG, CONST_INT}},			   \
+  {"reg_or_arith_cint_operand", {SUBREG, REG, CONST_INT}},		   \
   {"reg_or_logical_cint_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
-  {"got_operand", {SYMBOL_REF, CONST, LABEL_REF}},		\
-  {"got_no_const_operand", {SYMBOL_REF, LABEL_REF}},		\
-  {"easy_fp_constant", {CONST_DOUBLE}},				\
-  {"reg_or_mem_operand", {SUBREG, MEM, REG}},			\
-  {"lwa_operand", {SUBREG, MEM, REG}},				\
-  {"volatile_mem_operand", {MEM}},				\
-  {"offsettable_mem_operand", {MEM}},				\
-  {"mem_or_easy_const_operand", {SUBREG, MEM, CONST_DOUBLE}},	\
-  {"add_operand", {SUBREG, REG, CONST_INT}},			\
-  {"non_add_cint_operand", {CONST_INT}},			\
-  {"and_operand", {SUBREG, REG, CONST_INT}},			\
-  {"and64_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}},	\
-  {"logical_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}},	\
-  {"non_logical_cint_operand", {CONST_INT, CONST_DOUBLE}},	\
-  {"mask_operand", {CONST_INT}},				\
-  {"mask64_operand", {CONST_INT, CONST_DOUBLE}},		\
-  {"rldic_operand", {CONST_INT, CONST_DOUBLE}},			\
-  {"count_register_operand", {REG}},				\
-  {"xer_operand", {REG}},					\
-  {"call_operand", {SYMBOL_REF, REG}},				\
-  {"current_file_function_operand", {SYMBOL_REF}},		\
-  {"input_operand", {SUBREG, MEM, REG, CONST_INT, 		\
-		     CONST_DOUBLE, SYMBOL_REF}}, 		\
-  {"load_multiple_operation", {PARALLEL}},			\
-  {"store_multiple_operation", {PARALLEL}},			\
-  {"branch_comparison_operator", {EQ, NE, LE, LT, GE,		\
-				  GT, LEU, LTU, GEU, GTU,	\
-				  UNORDERED, ORDERED,		\
-				  UNEQ, LTGT,			\
-				  UNGE, UNGT, UNLE, UNLT}},	\
-  {"scc_comparison_operator", {EQ, NE, LE, LT, GE,		\
-			       GT, LEU, LTU, GEU, GTU}},	\
-  {"trap_comparison_operator", {EQ, NE, LE, LT, GE,		\
-				GT, LEU, LTU, GEU, GTU}},	\
-  {"boolean_operator", {AND, IOR, XOR}},			\
+  {"got_operand", {SYMBOL_REF, CONST, LABEL_REF}},			   \
+  {"got_no_const_operand", {SYMBOL_REF, LABEL_REF}},			   \
+  {"easy_fp_constant", {CONST_DOUBLE}},					   \
+  {"reg_or_mem_operand", {SUBREG, MEM, REG}},				   \
+  {"lwa_operand", {SUBREG, MEM, REG}},					   \
+  {"volatile_mem_operand", {MEM}},					   \
+  {"offsettable_mem_operand", {MEM}},					   \
+  {"mem_or_easy_const_operand", {SUBREG, MEM, CONST_DOUBLE}},		   \
+  {"add_operand", {SUBREG, REG, CONST_INT}},				   \
+  {"non_add_cint_operand", {CONST_INT}},				   \
+  {"and_operand", {SUBREG, REG, CONST_INT}},				   \
+  {"and64_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}},		   \
+  {"logical_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}},		   \
+  {"non_logical_cint_operand", {CONST_INT, CONST_DOUBLE}},		   \
+  {"mask_operand", {CONST_INT}},					   \
+  {"mask64_operand", {CONST_INT, CONST_DOUBLE}},			   \
+  {"rldic_operand", {CONST_INT, CONST_DOUBLE}},				   \
+  {"count_register_operand", {REG}},					   \
+  {"xer_operand", {REG}},						   \
+  {"call_operand", {SYMBOL_REF, REG}},					   \
+  {"current_file_function_operand", {SYMBOL_REF}},			   \
+  {"input_operand", {SUBREG, MEM, REG, CONST_INT,			   \
+		     CONST_DOUBLE, SYMBOL_REF}},			   \
+  {"load_multiple_operation", {PARALLEL}},				   \
+  {"store_multiple_operation", {PARALLEL}},				   \
+  {"branch_comparison_operator", {EQ, NE, LE, LT, GE,			   \
+				  GT, LEU, LTU, GEU, GTU,		   \
+				  UNORDERED, ORDERED,			   \
+				  UNGE, UNLE }},			   \
+  {"branch_positive_comparison_operator", {EQ, LT, GT, LTU, GTU,	   \
+					   UNORDERED }},		   \
+  {"scc_comparison_operator", {EQ, NE, LE, LT, GE,			   \
+			       GT, LEU, LTU, GEU, GTU,			   \
+			       UNORDERED, ORDERED,			   \
+			       UNGE, UNLE }},				   \
+  {"trap_comparison_operator", {EQ, NE, LE, LT, GE,			   \
+				GT, LEU, LTU, GEU, GTU}},		   \
+  {"boolean_operator", {AND, IOR, XOR}},				   \
   {"boolean_or_operator", {IOR, XOR}},
 
 /* uncomment for disabling the corresponding default options */
Index: gcc/config/rs6000/rs6000.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.98
diff -p -u -u -p -r1.98 rs6000.md
--- rs6000.md	2000/08/27 21:54:56	1.98
+++ rs6000.md	2000/09/06 05:53:38
@@ -37,7 +37,7 @@
 
 ;; Define an insn type attribute.  This is used in function unit delay
 ;; computations.
-(define_attr "type" "integer,load,store,fpload,fpstore,imul,lmul,idiv,ldiv,branch,compare,delayed_compare,fpcompare,mtjmpr,fp,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg"
+(define_attr "type" "integer,load,store,fpload,fpstore,imul,lmul,idiv,ldiv,branch,compare,cr_logical,delayed_compare,fpcompare,mtjmpr,fp,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg"
   (const_string "integer"))
 
 ;; Length (in bytes).
@@ -47,8 +47,8 @@
 				       (const_int -32768))
 				   (lt (minus (pc) (match_dup 0))
 				       (const_int 32767)))
-			      (const_int 8)
-			      (const_int 12))
+			      (const_int 4)
+			      (const_int 8))
 		(const_int 4)))
 
 ;; Processor type -- this attribute must exactly match the processor_type
@@ -124,6 +124,11 @@
   1 1)
 
 (define_function_unit "iu" 1 0
+  (and (eq_attr "type" "cr_logical")
+       (eq_attr "cpu" "rios1,rs64a,mpccore,ppc403,ppc601"))
+  1 1)
+
+(define_function_unit "iu" 1 0
   (and (eq_attr "type" "imul")
        (eq_attr "cpu" "ppc403"))
   4 4)
@@ -288,6 +293,15 @@
        (eq_attr "cpu" "ppc750"))
   19 19)
 
+; CR-logical operations are execute-serialized, that is they don't
+; start (and block the function unit) until all preceding operations
+; have finished.  They don't block dispatch of other insns, though.
+; I've imitated this by giving them longer latency.
+(define_function_unit "sru" 1 0 
+  (and (eq_attr "type" "cr_logical")
+       (eq_attr "cpu" "ppc603,ppc750"))
+  3 2)
+
 ; compare is done on integer unit, but feeds insns which
 ; execute on the branch unit.
 (define_function_unit "iu" 1 0   
@@ -357,6 +371,17 @@
        (eq_attr "cpu" "rs64a,mpccore,ppc403,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc750"))
   4 1)
 
+(define_function_unit "bpu" 1 0
+  (and (eq_attr "type" "cr_logical")
+       (eq_attr "cpu" "ppc604,ppc620"))
+  4 1)
+  
+(define_function_unit "cru" 1 0
+  (and (eq_attr "type" "cr_logical")
+       (eq_attr "cpu" "ppc604e"))
+  4 1)
+  
+
 ; all jumps/branches are executing on the bpu, in 1 cycle, for all machines.
 (define_function_unit "bpu" 1 0
   (eq_attr "type" "jmpreg")
@@ -9847,270 +9872,94 @@ operands[2] = GEN_INT (INTVAL (operands[
 }")
 
 (define_expand "beq"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (eq (match_dup 2)
-			  (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
-  operands[1] = gen_rtx_COMPARE (mode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (mode);
-}")
+  "{ rs6000_emit_cbranch (EQ, operands[0]); DONE; }")
 
 (define_expand "bne"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (ne (match_dup 2)
-			  (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
-  operands[1] = gen_rtx_COMPARE (mode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (mode);
-}")
+  "{ rs6000_emit_cbranch (NE, operands[0]); DONE; }")
 
-(define_expand "blt"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (lt (match_dup 2)
-			  (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+(define_expand "bge"
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
-  operands[1] = gen_rtx_COMPARE (mode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (mode);
-}")
+  "{ rs6000_emit_cbranch (GE, operands[0]); DONE; }")
 
 (define_expand "bgt"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (gt (match_dup 2)
-			  (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
-  operands[1] = gen_rtx_COMPARE (mode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (mode);
-}")
+  "{ rs6000_emit_cbranch (GT, operands[0]); DONE; }")
 
 (define_expand "ble"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (le (match_dup 2)
-			  (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
-  operands[1] = gen_rtx_COMPARE (mode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (mode);
-}")
+  "{ rs6000_emit_cbranch (LE, operands[0]); DONE; }")
 
-(define_expand "bge"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (ge (match_dup 2)
-			  (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+(define_expand "blt"
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ enum machine_mode mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
-  operands[1] = gen_rtx_COMPARE (mode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (mode);
-}")
+  "{ rs6000_emit_cbranch (LT, operands[0]); DONE; }")
 
-(define_expand "bgtu"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (gtu (match_dup 2)
-			   (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+(define_expand "bgeu"
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCUNSmode);
-}")
+  "{ rs6000_emit_cbranch (GEU, operands[0]); DONE; }")
 
-(define_expand "bltu"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (ltu (match_dup 2)
-			   (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+(define_expand "bgtu"
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCUNSmode);
-}")
+  "{ rs6000_emit_cbranch (GTU, operands[0]); DONE; }")
 
-(define_expand "bgeu"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (geu (match_dup 2)
-			   (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+(define_expand "bleu"
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCUNSmode);
-}")
+  "{ rs6000_emit_cbranch (LEU, operands[0]); DONE; }")
 
-(define_expand "bleu"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (leu (match_dup 2)
-			   (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+(define_expand "bltu"
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ operands[1] = gen_rtx_COMPARE (CCUNSmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCUNSmode);
-}")
+  "{ rs6000_emit_cbranch (LTU, operands[0]); DONE; }")
 
 (define_expand "bunordered"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (unordered (match_dup 2)
-			         (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ if (!rs6000_compare_fp_p) FAIL;
-  operands[1] = gen_rtx_COMPARE (CCFPmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCFPmode);
-}")
+  "{ rs6000_emit_cbranch (UNORDERED, operands[0]); DONE; }")
 
 (define_expand "bordered"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (ordered (match_dup 2)
-			       (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ if (!rs6000_compare_fp_p) FAIL;
-  operands[1] = gen_rtx_COMPARE (CCFPmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCFPmode);
-}")
+  "{ rs6000_emit_cbranch (ORDERED, operands[0]); DONE; }")
 
 (define_expand "buneq"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (uneq (match_dup 2)
-			    (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ if (!rs6000_compare_fp_p) FAIL;
-  operands[1] = gen_rtx_COMPARE (CCFPmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCFPmode);
-}")
+  "{ rs6000_emit_cbranch (UNEQ, operands[0]); DONE; }")
 
 (define_expand "bunge"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (unge (match_dup 2)
-			    (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ if (!rs6000_compare_fp_p) FAIL;
-  operands[1] = gen_rtx_COMPARE (CCFPmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCFPmode);
-}")
+  "{ rs6000_emit_cbranch (UNGE, operands[0]); DONE; }")
 
 (define_expand "bungt"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (ungt (match_dup 2)
-			    (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ if (!rs6000_compare_fp_p) FAIL;
-  operands[1] = gen_rtx_COMPARE (CCFPmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCFPmode);
-}")
+  "{ rs6000_emit_cbranch (UNGT, operands[0]); DONE; }")
 
 (define_expand "bunle"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (unle (match_dup 2)
-			    (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ if (!rs6000_compare_fp_p) FAIL;
-  operands[1] = gen_rtx_COMPARE (CCFPmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCFPmode);
-}")
+  "{ rs6000_emit_cbranch (UNLE, operands[0]); DONE; }")
 
 (define_expand "bunlt"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (unlt (match_dup 2)
-			    (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ if (!rs6000_compare_fp_p) FAIL;
-  operands[1] = gen_rtx_COMPARE (CCFPmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCFPmode);
-}")
+  "{ rs6000_emit_cbranch (UNLT, operands[0]); DONE; }")
 
 (define_expand "bltgt"
-  [(set (match_dup 2) (match_dup 1))
-   (set (pc)
-	(if_then_else (ltgt (match_dup 2)
-			    (const_int 0))
-		      (label_ref (match_operand 0 "" ""))
-		      (pc)))]
+  [(use (match_operand 0 "" ""))]
   ""
-  "
-{ if (!rs6000_compare_fp_p) FAIL;
-  operands[1] = gen_rtx_COMPARE (CCFPmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCFPmode);
-}")
+  "{ rs6000_emit_cbranch (LTGT, operands[0]); DONE; }")
 
 ;; For SNE, we would prefer that the xor/abs sequence be used for integers.
 ;; For SEQ, likewise, except that comparisons with zero should be done
@@ -10118,261 +9967,85 @@ operands[2] = GEN_INT (INTVAL (operands[
 ;; resulting insns, we must, in fact, allow SEQ for integers.  Fail in
 ;; the cases we don't want to handle.
 (define_expand "seq"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_operand:SI 0 "gpc_reg_operand" "")
-	(eq:SI (match_dup 2) (const_int 0)))]
+  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
   ""
-  "
-{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
-  operands[1] = gen_rtx_COMPARE (mode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (mode);
-
-  op_mode = GET_MODE (rs6000_compare_op0);
-  if (op_mode == VOIDmode)
-    op_mode = GET_MODE (rs6000_compare_op1);
+  "{ rs6000_emit_sCOND (EQ, operands[0]); DONE; }")
 
-  if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
-      convert_move (operands[0],
-		    gen_rtx_EQ (DImode, operands[2], const0_rtx), 0);
-      DONE;
-    }
-}")
-
 (define_expand "sne"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_operand:SI 0 "gpc_reg_operand" "")
-	(ne:SI (match_dup 2) (const_int 0)))]
+  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
   ""
   "
-{ if (! rs6000_compare_fp_p)
+{ 
+  if (! rs6000_compare_fp_p)
     FAIL;
-
-  operands[1] = gen_rtx_COMPARE (CCFPmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCFPmode);
 
-  if (TARGET_POWERPC64)
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
-      convert_move (operands[0],
-		    gen_rtx_NE (DImode, operands[2], const0_rtx), 0);
-      DONE;
-    }
+  rs6000_emit_sCOND (NE, operands[0]); 
+  DONE;
 }")
 
 ;; A > 0 is best done using the portable sequence, so fail in that case.
 (define_expand "sgt"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_operand:SI 0 "gpc_reg_operand" "")
-	(gt:SI (match_dup 2) (const_int 0)))]
+  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
   ""
   "
-{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
-
+{ 
   if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
     FAIL;
 
-  operands[1] = gen_rtx_COMPARE (mode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (mode);
-
-  op_mode = GET_MODE (rs6000_compare_op0);
-  if (op_mode == VOIDmode)
-    op_mode = GET_MODE (rs6000_compare_op1);
-
-  if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
-      convert_move (operands[0],
-		    gen_rtx_GT (DImode, operands[2], const0_rtx), 0);
-      DONE;
-    }
+  rs6000_emit_sCOND (GT, operands[0]); 
+  DONE;
 }")
 
 ;; A < 0 is best done in the portable way for A an integer.
 (define_expand "slt"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_operand:SI 0 "gpc_reg_operand" "")
-	(lt:SI (match_dup 2) (const_int 0)))]
+  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
   ""
   "
-{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
-
+{ 
   if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
     FAIL;
 
-  operands[1] = gen_rtx_COMPARE (mode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (mode);
-
-  op_mode = GET_MODE (rs6000_compare_op0);
-  if (op_mode == VOIDmode)
-    op_mode = GET_MODE (rs6000_compare_op1);
-
-  if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
-      convert_move (operands[0],
-		    gen_rtx_LT (DImode, operands[2], const0_rtx), 0);
-      DONE;
-    }
+  rs6000_emit_sCOND (LT, operands[0]); 
+  DONE;
 }")
 
 (define_expand "sge"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_operand:SI 0 "gpc_reg_operand" "")
-	(ge:SI (match_dup 2) (const_int 0)))]
+  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
   ""
-  "
-{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
-  operands[1] = gen_rtx_COMPARE (mode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (mode);
-
-  op_mode = GET_MODE (rs6000_compare_op0);
-  if (op_mode == VOIDmode)
-    op_mode = GET_MODE (rs6000_compare_op1);
+  "{ rs6000_emit_sCOND (GE, operands[0]); DONE; }")
 
-  if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
-      convert_move (operands[0],
-		    gen_rtx_GE (DImode, operands[2], const0_rtx), 0);
-      DONE;
-    }
-}")
-
 ;; A <= 0 is best done the portable way for A an integer.
 (define_expand "sle"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_operand:SI 0 "gpc_reg_operand" "")
-	(le:SI (match_dup 2) (const_int 0)))]
+  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
   ""
   "
-{ enum machine_mode op_mode, mode = rs6000_compare_fp_p ? CCFPmode : CCmode;
-
+{ 
   if (! rs6000_compare_fp_p && rs6000_compare_op1 == const0_rtx)
     FAIL;
 
-  operands[1] = gen_rtx_COMPARE (mode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (mode);
-
-  op_mode = GET_MODE (rs6000_compare_op0);
-  if (op_mode == VOIDmode)
-    op_mode = GET_MODE (rs6000_compare_op1);
-
-  if (TARGET_POWERPC64 && (op_mode == DImode || rs6000_compare_fp_p))
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
-      convert_move (operands[0],
-		    gen_rtx_LE (DImode, operands[2], const0_rtx), 0);
-      DONE;
-    }
+  rs6000_emit_sCOND (LE, operands[0]); 
+  DONE;
 }")
 
 (define_expand "sgtu"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_operand:SI 0 "gpc_reg_operand" "")
-	(gtu:SI (match_dup 2) (const_int 0)))]
+  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
   ""
-  "
-{ enum machine_mode op_mode;
-
-  operands[1] = gen_rtx_COMPARE (CCUNSmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCUNSmode);
-
-  op_mode = GET_MODE (rs6000_compare_op0);
-  if (op_mode == VOIDmode)
-    op_mode = GET_MODE (rs6000_compare_op1);
+  "{ rs6000_emit_sCOND (GTU, operands[0]); DONE; }")
 
-  if (TARGET_POWERPC64 && op_mode == DImode)
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
-      convert_move (operands[0],
-		    gen_rtx_GTU (DImode, operands[2], const0_rtx), 0);
-      DONE;
-    }
-}")
-
 (define_expand "sltu"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_operand:SI 0 "gpc_reg_operand" "")
-	(ltu:SI (match_dup 2) (const_int 0)))]
+  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
   ""
-  "
-{ enum machine_mode op_mode;
-
-  operands[1] = gen_rtx_COMPARE (CCUNSmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCUNSmode);
+  "{ rs6000_emit_sCOND (LTU, operands[0]); DONE; }")
 
-  op_mode = GET_MODE (rs6000_compare_op0);
-  if (op_mode == VOIDmode)
-    op_mode = GET_MODE (rs6000_compare_op1);
-
-  if (TARGET_POWERPC64 && op_mode == DImode)
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
-      convert_move (operands[0],
-		    gen_rtx_LTU (DImode, operands[2], const0_rtx), 0);
-      DONE;
-    }
-}")
-
 (define_expand "sgeu"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_operand:SI 0 "gpc_reg_operand" "")
-	(geu:SI (match_dup 2) (const_int 0)))]
+  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
   ""
-  "
-{ enum machine_mode op_mode;
-
-  operands[1] = gen_rtx_COMPARE (CCUNSmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCUNSmode);
-
-  op_mode = GET_MODE (rs6000_compare_op0);
-  if (op_mode == VOIDmode)
-    op_mode = GET_MODE (rs6000_compare_op1);
-
-  if (TARGET_POWERPC64 && op_mode == DImode)
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
-      convert_move (operands[0],
-		    gen_rtx_GEU (DImode, operands[2], const0_rtx), 0);
-      DONE;
-    }
-}")
+  "{ rs6000_emit_sCOND (GEU, operands[0]); DONE; }")
 
 (define_expand "sleu"
-  [(set (match_dup 2) (match_dup 1))
-   (set (match_operand:SI 0 "gpc_reg_operand" "")
-	(leu:SI (match_dup 2) (const_int 0)))]
+  [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
   ""
-  "
-{ enum machine_mode op_mode;
-
-  operands[1] = gen_rtx_COMPARE (CCUNSmode,
-				 rs6000_compare_op0, rs6000_compare_op1);
-  operands[2] = gen_reg_rtx (CCUNSmode);
-
-  op_mode = GET_MODE (rs6000_compare_op0);
-  if (op_mode == VOIDmode)
-    op_mode = GET_MODE (rs6000_compare_op1);
-
-  if (TARGET_POWERPC64 && op_mode == DImode)
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, operands[2], operands[1]));
-      convert_move (operands[0],
-		    gen_rtx_LEU (DImode, operands[2], const0_rtx), 0);
-      DONE;
-    }
-}")
+  "{ rs6000_emit_sCOND (LEU, operands[0]); DONE; }")
 
 ;; Here are the actual compare insns.
 (define_insn "*cmpsi_internal1"
@@ -10632,38 +10305,6 @@ operands[2] = GEN_INT (INTVAL (operands[
 		    (const_int 0)))]
   "")
 
-;; If we are comparing the result of two comparisons, this can be done
-;; using creqv or crxor.
-
-(define_insn ""
-  [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y")
-	(compare:CCEQ (match_operator 1 "scc_comparison_operator"
-			      [(match_operand 2 "cc_reg_operand" "y")
-			       (const_int 0)])
-		      (match_operator 3 "scc_comparison_operator"
-			      [(match_operand 4 "cc_reg_operand" "y")
-			       (const_int 0)])))]
-  "REGNO (operands[2]) != REGNO (operands[4])"
-  "*
-{
-  enum rtx_code code1, code2;
-
-  code1 = GET_CODE (operands[1]);
-  code2 = GET_CODE (operands[3]);
-
-  if ((code1 == EQ || code1 == LT || code1 == GT
-       || code1 == LTU || code1 == GTU
-       || (code1 != NE && GET_MODE (operands[2]) == CCFPmode))
-      !=
-      (code2 == EQ || code2 == LT || code2 == GT
-       || code2 == LTU || code2 == GTU
-       || (code2 != NE && GET_MODE (operands[4]) == CCFPmode)))
-    return \"%C1%C3crxor %E0,%j1,%j3\";
-  else
-    return \"%C1%C3creqv %E0,%j1,%j3\";
-}"
-  [(set_attr "length" "12")])
-
 ;; There is a 3 cycle delay between consecutive mfcr instructions
 ;; so it is useful to combine 2 scc instructions to use only one mfcr.
 
@@ -13153,7 +12794,7 @@ operands[2] = GEN_INT (INTVAL (operands[
   return output_cbranch (operands[0], NULL, 0, insn);
 }"
   [(set_attr "type" "branch")
-   (set_attr "length" "8")])
+   (set_attr "length" "4")])
 
 (define_insn ""
   [(set (pc)
@@ -13184,7 +12825,112 @@ operands[2] = GEN_INT (INTVAL (operands[
   return output_cbranch (operands[0], NULL, 1, insn);
 }"
   [(set_attr "type" "branch")
-   (set_attr "length" "8")])
+   (set_attr "length" "4")])
+
+;; Logic on condition register values.
+
+; This pattern matches things like
+; (set (reg:CCEQ 68) (compare:CCEQ (ior:SI (gt:SI (reg:CCFP 68) (const_int 0))
+;					   (eq:SI (reg:CCFP 68) (const_int 0)))
+;				   (const_int 1)))
+; which are generated by the branch logic.
+
+(define_insn ""
+  [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y")
+        (compare:CCEQ (match_operator:SI 1 "boolean_operator"
+	                [(match_operator:SI 2 
+				      "branch_positive_comparison_operator"
+				      [(match_operand 3
+						      "cc_reg_operand" "y")
+				       (const_int 0)])
+	                 (match_operator:SI 4 
+				      "branch_positive_comparison_operator"
+				      [(match_operand 5
+						      "cc_reg_operand" "y")
+				       (const_int 0)])])
+		      (const_int 1)))]
+  ""
+  "cr%q1 %E0,%j2,%j4"
+  [(set_attr "type" "cr_logical")])
+
+; Why is the constant -1 here, but 1 in the previous pattern?
+; Because ~1 has all but the low bit set.
+(define_insn ""
+  [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y")
+        (compare:CCEQ (match_operator:SI 1 "boolean_or_operator"
+	                [(not:SI (match_operator:SI 2 
+				      "branch_positive_comparison_operator"
+				      [(match_operand 3
+						      "cc_reg_operand" "y")
+				       (const_int 0)]))
+	                 (match_operator:SI 4
+				"branch_positive_comparison_operator"
+				[(match_operand 5
+						"cc_reg_operand" "y")
+				 (const_int 0)])])
+		      (const_int -1)))]
+  ""
+  "cr%q1 %E0,%j2,%j4"
+  [(set_attr "type" "cr_logical")])
+
+(define_insn ""
+  [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y")
+	(compare:CCEQ (match_operator:SI 2 
+				      "branch_positive_comparison_operator"
+				      [(match_operand 3
+						      "cc_reg_operand" "y")
+				       (const_int 0)])
+		      (const_int 0)))]
+  ""
+  "crnot %E0,%j2"
+  [(set_attr "type" "cr_logical")])
+
+;; If we are comparing the result of two comparisons, this can be done
+;; using creqv or crxor.
+
+(define_insn_and_split ""
+  [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y")
+	(compare:CCEQ (match_operator 1 "branch_comparison_operator"
+			      [(match_operand 2 "cc_reg_operand" "y")
+			       (const_int 0)])
+		      (match_operator 3 "branch_comparison_operator"
+			      [(match_operand 4 "cc_reg_operand" "y")
+			       (const_int 0)])))]
+  ""
+  "#"
+  ""
+  [(set (match_dup 0) (compare:CCEQ (xor:SI (match_dup 1) (match_dup 3))
+				    (match_dup 5)))]
+  "
+{
+  int positive_1, positive_2;
+
+  positive_1 = branch_positive_comparison_operator (operands[1], CCEQmode);
+  positive_2 = branch_positive_comparison_operator (operands[3], CCEQmode);
+
+  if (! positive_1)
+    operands[1] = gen_rtx (SImode,
+			   rs6000_reverse_condition (GET_MODE (operands[2]),
+						     GET_CODE (operands[1])),
+			   operands[2]);
+  else if (GET_MODE (operands[1]) != SImode)
+    operands[1] = gen_rtx (SImode,
+			   GET_CODE (operands[1]),
+			   operands[2]);
+
+  if (! positive_2)
+    operands[3] = gen_rtx (SImode,
+			   rs6000_reverse_condition (GET_MODE (operands[4]),
+						     GET_CODE (operands[3])),
+			   operands[4]);
+  else if (GET_MODE (operands[3]) != SImode)
+    operands[3] = gen_rtx (SImode,
+			   GET_CODE (operands[3]),
+			   operands[4]);
+
+  if (positive_1 == positive_2)
+    operands[1] = gen_rtx_NOT (SImode, operands[1]);
+}")
 
 ;; Unconditional branch and return.
 
============================================================

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