diff mbox

[RFC] Add a new argument to SELECT_CC_MODE

Message ID 4D4D94D1.4040606@codesourcery.com
State New
Headers show

Commit Message

Jie Zhang Feb. 5, 2011, 6:20 p.m. UTC
arm-none-linux-gnueabi GCC now generate fcmpes instruction for the 
following function with option "-O2 -mfloat-abi=softfp -mfpu=vfp":

float
foo (float x, float y)
{
   return __builtin_isgreaterequal (x, y) ? x : y;
}

fcmpes will cause an exception when one operand is NaN, while 
__builtin_isgreaterequal should not cause an exception when one operand 
is NaN. We should use fcmps instruction instead.

GCC 4.4.x generates fcmps but since 4.5 GCC fcmpes is generated.

The problem is in combine pass. Before combine:

(insn 8 4 9 2 (set (reg:CCFP 24 cc)
         (compare:CCFP (reg/v:SF 136 [ x ])
             (reg/v:SF 137 [ y ]))) test.c:4 675 {*cmpsf_split_vfp}
      (nil))

(insn 9 8 11 2 (set (reg:SI 139)
         (unlt:SI (reg:CCFP 24 cc)
             (const_int 0 [0]))) test.c:4 212 {*mov_scc}
      (expr_list:REG_DEAD (reg:CCFP 24 cc)
         (nil)))

(insn 11 9 12 2 (set (reg:SI 140)
         (and:SI (reg:SI 139)
             (const_int 255 [0xff]))) test.c:4 69 {*arm_andsi3_insn}
      (expr_list:REG_DEAD (reg:SI 139)
         (nil)))

(insn 12 11 53 2 (set (reg:CC 24 cc)
         (compare:CC (reg:SI 140)
             (const_int 0 [0]))) test.c:4 198 {*arm_cmpsi_insn}
      (expr_list:REG_DEAD (reg:SI 140)
         (nil)))

After combine:

(note 8 4 9 2 NOTE_INSN_DELETED)

(note 9 8 11 2 NOTE_INSN_DELETED)

(note 11 9 12 2 NOTE_INSN_DELETED)

(insn 12 11 53 2 (set (reg:CCFPE 24 cc)
         (compare:CCFPE (reg/v:SF 136 [ x ])
             (reg/v:SF 137 [ y ]))) test.c:4 676 {*cmpsf_trap_split_vfp}
      (nil))

We can see that before combine pass, CCFPmode is used. After the combine 
pass, CCFPEmode is used, which causes fcmpes to be used.

When combine pass combines the above instructions, it calls 
SELECT_CC_MODE to select a proper mode for code GE and two operands: 
(reg:SF x) and (reg:SF y). The problem is the original information (no 
exception) contained in CCFPmode is lost, so CCFPEmode is chosen.

This patch adds a new argument to SELECT_CC_MODE to allow combine pass 
to pass the original mode to SELECT_CC_MODE, thus targets can get the 
information to choose a better mode.

Regression tested for arm-none-eabi target with option "-march=armv7-a 
-mfloat-abi=softfp -mfpu=neon" on qemu for gcc, g++, libstdc++. Tested 
the new test for arm-none-linux-gnueabi on qemu. Build x86_64-linux-gnu 
native GCC is OK.

Is there a better way to fix this issue? Is this patch OK?


Regards,

Comments

Eric Botcazou Feb. 5, 2011, 8:08 p.m. UTC | #1
> When combine pass combines the above instructions, it calls
> SELECT_CC_MODE to select a proper mode for code GE and two operands:
> (reg:SF x) and (reg:SF y). The problem is the original information (no
> exception) contained in CCFPmode is lost, so CCFPEmode is chosen.

What has been changed in simplify_set before the call to SELECT_CC_MODE?  That 
is, I presume that OP0 and OP1 haven't been changed, but what about NEW_CODE?
If nothing has been changed, we can probably skip the call to SELECT_CC_MODE.
Jie Zhang Feb. 6, 2011, 2:45 a.m. UTC | #2
On 02/06/2011 04:08 AM, Eric Botcazou wrote:
>> When combine pass combines the above instructions, it calls
>> SELECT_CC_MODE to select a proper mode for code GE and two operands:
>> (reg:SF x) and (reg:SF y). The problem is the original information (no
>> exception) contained in CCFPmode is lost, so CCFPEmode is chosen.
>
> What has been changed in simplify_set before the call to SELECT_CC_MODE?  That
> is, I presume that OP0 and OP1 haven't been changed, but what about NEW_CODE?
> If nothing has been changed, we can probably skip the call to SELECT_CC_MODE.
>
Thanks for review!

OP0 and OP1 have been changed. When entering simplify_set:

(gdb) p x
$6 = (rtx) 0x7ffff719d5e8
(gdb) pr
(set (reg:CCFP 24 cc)
     (compare:CCFP (compare:CCFP (reg/v:SF 136 [ x ])
             (reg/v:SF 137 [ y ]))
         (const_int 0 [0])))

Before simplify_relational_operation:

(gdb) p old_code
$9 = GE
(gdb) p compare_mode
$10 = CCFPmode
(gdb) p op0
$11 = (rtx) 0x7ffff719d4b0
(gdb) pr
(compare:CCFP (reg/v:SF 136 [ x ])
     (reg/v:SF 137 [ y ]))
(gdb) p op1
$12 = (rtx) 0x7ffff70ba470
(gdb) pr
(const_int 0 [0])

After simplify_relational_operation and just before simplify_comparison:

(gdb) p tmp
$14 = (rtx) 0x7ffff719d420
(gdb) pr
(ge:CCFP (reg/v:SF 136 [ x ])
     (reg/v:SF 137 [ y ]))
(gdb) p new_code
$15 = GE
(gdb) p op0
$16 = (rtx) 0x7ffff719aca0
(gdb) pr
(reg/v:SF 136 [ x ])
(gdb) p op1
$17 = (rtx) 0x7ffff719ace0
(gdb) pr
(reg/v:SF 137 [ y ])

simplify_comparison does not change NEW_CODE, OP0, OP1. And we come to 
the code calling SELECT_CC_MODE.

   compare_mode = SELECT_CC_MODE (new_code, op0, op1);

So comparing to X at the beginning of simplify_set, both OP0 and OP1 
have been changed.


Regards,
--
Jie Zhang
diff mbox

Patch


	* compare-elim.c (maybe_select_cc_mode): Update calls to
	SELECT_CC_MODE.
	* combine (try_combine): Likewise.
	(simplify_set): Pass original compare mode to SELECT_CC_MODE.
	* config/frv/frv.h (SELECT_CC_MODE): Update.
	* config/frv/frv.c (frv_emit_comparison): Update call to
	SELECT_CC_MODE.
	* config/s390/s390.h (SELECT_CC_MODE): Update.
	* config/sparc/sparc.c (gen_comapre_reg_1): Update call to
	SELECT_CC_MODE.
	* config/sparc/sparc.h (SELECT_CC_MODE): Update.
	* config/mep/mep.h (SELECT_CC_MODE): Likewise.
	* config/rx/rx.h (SELECT_CC_MODE): Likewise.
	* config/i386/i386.h (SELECT_CC_MODE): Likewise.
	* config/i386/i386.md (fp_jcc_1_387, fp_jcc_1r_387,
	fp_jcc_3_387): Update calls to SELECT_CC_MODE.
	* config/i386/i386.c (ix86_expand_int_compare): Likewise.
	* config/pdp11/pdp11.h(SELECT_CC_MODE): Update.
	* config/mn10300/mn10300.h (SELECT_CC_MODE): Update.
	* config/ia64/ia64.h (SELECT_CC_MDOE): Update.
	* config/rs6000/rs6000.h (SELECT_CC_MODE): Update.
	* config/arc/arc.c (gen_compare_reg): Update call to
	SELECT_CC_MODE.
	* config/arc/arc.h (SELECT_CC_MODE): Update.
	* config/score/score.h (SELECT_CC_MODE): Update.
	* config/arm/arm.c (arm_select_dominance_cc_mode): Update
	calls to arm_select_cc_mode.
	(arm_select_cc_mode): Use the new added mode argument.
	Don't change CCFPmode or CCFPEmode if one of them is preferred
	and can be used for the given operands.
	(arm_gen_compare_reg, get_arm_condition_code): Update call to
	SELECT_CC_MODE.
	* config/arm/arm.h (SELECT_CC_MODE): Update.
	* config/arm/arm-protos.h (arm_select_cc_mode): Update declaration
	of arm_select_cc_mode.
	* config/arm/arm.md (compare_scc, and_scc_scc_nod,
	and 4 define_splits): Update calls to SELECT_CC_MODE.
	* config/pa/pa.h (SELECT_CC_MODE): Update.
	* config/v850/v850.h (SELECT_CC_MODE): Update.
	* config/mmix/mmix.h (SELECT_CC_MODE): Update.
	* config/mmix/mmix.c (mmix_gen_compare_reg): Update call to
	SELECT_CC_MODE.
	* doc/tm.texi.in: Docutment the new mode argument for
	SELECT_CC_MODE.
	* doc/tm.texi: Regenerate.

	testsuite/
	* gcc.target/arm/fp-comp-builtin.c: New test.


Index: doc/tm.texi.in
===================================================================
--- doc/tm.texi.in	(revision 169850)
+++ doc/tm.texi.in	(working copy)
@@ -5900,7 +5900,7 @@  two places, the @file{md} file and in @c
 @findex CCmode
 @findex MODE_CC
 
-@defmac SELECT_CC_MODE (@var{op}, @var{x}, @var{y})
+@defmac SELECT_CC_MODE (@var{op}, @var{x}, @var{y}, @var{mode})
 On many machines, the condition code may be produced by other instructions
 than compares, for example the branch can use directly the condition
 code set by a subtract instruction.  However, on some machines
@@ -5914,9 +5914,12 @@  unsigned comparison) produced the condit
 
 If other modes than @code{CCmode} are required, add them to
 @file{@var{machine}-modes.def} and define @code{SELECT_CC_MODE} to choose
-a mode given an operand of a compare.  This is needed because the modes
+a mode given operands of a compare.  This is needed because the modes
 have to be chosen not only during RTL generation but also, for example,
-by instruction combination.  The result of @code{SELECT_CC_MODE} should
+by instruction combination.  When @var{mode} is not @code{VOIDmode},
+it's preferred if it can be used for the given operands.  This is used
+by instruction combination to assist some targets, like the ARM, to
+choose better mode.  The result of @code{SELECT_CC_MODE} should
 be consistent with the mode used in the patterns; for example to support
 the case of the add on the SPARC discussed above, we have the pattern
 
Index: testsuite/gcc.target/arm/fp-comp-builtin.c
===================================================================
--- testsuite/gcc.target/arm/fp-comp-builtin.c	(revision 0)
+++ testsuite/gcc.target/arm/fp-comp-builtin.c	(revision 0)
@@ -0,0 +1,12 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -mfpu=vfp -mfloat-abi=softfp" } */
+/* { dg-require-effective-target arm_vfp_ok } */
+
+float
+foo (float x, float y)
+{
+  return __builtin_isgreaterequal (x, y) ? x : y;
+}
+
+/* { dg-final { scan-assembler "fcmps" } } */
+/* { dg-final { scan-assembler-not "fcmpes" } } */
Index: compare-elim.c
===================================================================
--- compare-elim.c	(revision 169850)
+++ compare-elim.c	(working copy)
@@ -425,7 +425,7 @@  maybe_select_cc_mode (struct comparison
      common case of exactly one use.  */
   if (n == 1)
     {
-      sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
+      sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b, VOIDmode);
       if (sel_mode != cmp->orig_mode)
 	{
 	  flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
@@ -436,11 +436,11 @@  maybe_select_cc_mode (struct comparison
     {
       int i;
 
-      sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
+      sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b, VOIDmode);
       for (i = 1; i < n; ++i)
 	{
 	  enum machine_mode new_mode;
-	  new_mode = SELECT_CC_MODE (cmp->uses[i].code, a, b);
+	  new_mode = SELECT_CC_MODE (cmp->uses[i].code, a, b, VOIDmode);
 	  if (new_mode != sel_mode)
 	    {
 	      sel_mode = targetm.cc_modes_compatible (sel_mode, new_mode);
Index: combine.c
===================================================================
--- combine.c	(revision 169850)
+++ combine.c	(working copy)
@@ -3030,7 +3030,7 @@  try_combine (rtx i3, rtx i2, rtx i1, rtx
 	  && (cc_use = find_single_use (SET_DEST (newpat), i3,
 					&undobuf.other_insn))
 	  && ((compare_mode = SELECT_CC_MODE (GET_CODE (*cc_use),
-					      i2src, const0_rtx))
+					      i2src, const0_rtx, VOIDmode))
 	      != GET_MODE (SET_DEST (newpat))))
 	{
 	  if (can_change_dest_mode (SET_DEST (newpat), added_sets_2,
@@ -6288,7 +6288,7 @@  simplify_set (rtx x)
       if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_CC)
 	compare_mode = GET_MODE (op0);
       else
-	compare_mode = SELECT_CC_MODE (new_code, op0, op1);
+	compare_mode = SELECT_CC_MODE (new_code, op0, op1, compare_mode);
 
 #ifndef HAVE_cc0
       /* If the mode changed, we have to change SET_DEST, the mode in the
Index: config/frv/frv.h
===================================================================
--- config/frv/frv.h	(revision 169850)
+++ config/frv/frv.h	(working copy)
@@ -1680,7 +1680,7 @@  __asm__("\n"								\
 
 /* We define extra CC modes in frv-modes.def so we need a selector.  */
 
-#define SELECT_CC_MODE frv_select_cc_mode
+#define SELECT_CC_MODE(OP,X,Y,M) frv_select_cc_mode ((OP), (X), (Y))
 
 /* A C expression whose value is one if it is always safe to reverse a
    comparison whose mode is MODE.  If `SELECT_CC_MODE' can ever return MODE for
Index: config/frv/frv.c
===================================================================
--- config/frv/frv.c	(revision 169850)
+++ config/frv/frv.c	(working copy)
@@ -4807,7 +4807,7 @@  frv_emit_comparison (enum rtx_code test,
 
   /* Possibly disable using anything but a fixed register in order to work
      around cse moving comparisons past function calls.  */
-  cc_mode = SELECT_CC_MODE (test, op0, op1);
+  cc_mode = SELECT_CC_MODE (test, op0, op1, VOIDmode);
   cc_reg = ((TARGET_ALLOC_CC)
 	    ? gen_reg_rtx (cc_mode)
 	    : gen_rtx_REG (cc_mode,
Index: config/s390/s390.h
===================================================================
--- config/s390/s390.h	(revision 169850)
+++ config/s390/s390.h	(working copy)
@@ -767,7 +767,7 @@  ((GET_CODE (X) == SYMBOL_REF && tls_symb
 
 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
    return the mode to be used for the comparison.  */
-#define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))
+#define SELECT_CC_MODE(OP, X, Y, M) s390_select_ccmode ((OP), (X), (Y))
 
 /* Canonicalize a comparison from one we don't have to one we do have.  */
 #define CANONICALIZE_COMPARISON(CODE, OP0, OP1) \
Index: config/sparc/sparc.c
===================================================================
--- config/sparc/sparc.c	(revision 169850)
+++ config/sparc/sparc.c	(working copy)
@@ -2099,7 +2099,7 @@  gen_compare_reg_1 (enum rtx_code code, r
   if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
     return x;
 
-  mode = SELECT_CC_MODE (code, x, y);
+  mode = SELECT_CC_MODE (code, x, y, VOIDmode);
 
   /* ??? We don't have movcc patterns so we cannot generate pseudo regs for the
      fcc regs (cse can't tell they're really call clobbered regs and will
Index: config/sparc/sparc.h
===================================================================
--- config/sparc/sparc.h	(revision 169850)
+++ config/sparc/sparc.h	(working copy)
@@ -1758,7 +1758,7 @@  (! TARGET_PTR64 ? SImode : flag_pic ? DI
    CCFP[E]mode is used.  CC_NOOVmode should be used when the first operand
    is a PLUS, MINUS, NEG, or ASHIFT.  CCmode should be used when no special
    processing is needed.  */
-#define SELECT_CC_MODE(OP,X,Y)  select_cc_mode ((OP), (X), (Y))
+#define SELECT_CC_MODE(OP,X,Y,M)  select_cc_mode ((OP), (X), (Y))
 
 /* Return nonzero if MODE implies a floating point inequality can be
    reversed.  For SPARC this is always true because we have a full
Index: config/mep/mep.h
===================================================================
--- config/mep/mep.h	(revision 169850)
+++ config/mep/mep.h	(working copy)
@@ -573,7 +573,7 @@  typedef struct
 #define LEGITIMATE_CONSTANT_P(X) \
   mep_legitimate_constant_p(X)
 
-#define SELECT_CC_MODE(OP, X, Y)  CCmode
+#define SELECT_CC_MODE(OP, X, Y, M)  CCmode
 
 
 /* Moves between control regs need a scratch.  */
Index: config/rx/rx.h
===================================================================
--- config/rx/rx.h	(revision 169850)
+++ config/rx/rx.h	(working copy)
@@ -623,4 +623,4 @@  typedef unsigned int CUMULATIVE_ARGS;
 #define BRANCH_COST(SPEED,PREDICT)       1
 #define REGISTER_MOVE_COST(MODE,FROM,TO) 2
 
-#define SELECT_CC_MODE(OP,X,Y)  rx_select_cc_mode(OP, X, Y)
+#define SELECT_CC_MODE(OP,X,Y,M)  rx_select_cc_mode(OP, X, Y)
Index: config/i386/i386.h
===================================================================
--- config/i386/i386.h	(revision 169850)
+++ config/i386/i386.h	(working copy)
@@ -1844,7 +1844,7 @@  do {							\
    For integer comparisons against zero, reduce to CCNOmode or CCZmode if
    possible, to allow for more combinations.  */
 
-#define SELECT_CC_MODE(OP, X, Y) ix86_cc_mode ((OP), (X), (Y))
+#define SELECT_CC_MODE(OP, X, Y, M) ix86_cc_mode ((OP), (X), (Y))
 
 /* Return nonzero if MODE implies a floating point inequality can be
    reversed.  */
Index: config/i386/i386.md
===================================================================
--- config/i386/i386.md	(revision 169850)
+++ config/i386/i386.md	(working copy)
@@ -10948,7 +10948,7 @@  (define_insn "*fp_jcc_1_387"
    && (GET_MODE (operands[1]) == SFmode || GET_MODE (operands[1]) == DFmode)
    && GET_MODE (operands[1]) == GET_MODE (operands[2])
    && SELECT_CC_MODE (GET_CODE (operands[0]),
-		      operands[1], operands[2]) == CCFPmode
+		      operands[1], operands[2], VOIDmode) == CCFPmode
    && !TARGET_CMOVE"
   "#")
 
@@ -10966,7 +10966,7 @@  (define_insn "*fp_jcc_1r_387"
    && (GET_MODE (operands[1]) == SFmode || GET_MODE (operands[1]) == DFmode)
    && GET_MODE (operands[1]) == GET_MODE (operands[2])
    && SELECT_CC_MODE (GET_CODE (operands[0]),
-		      operands[1], operands[2]) == CCFPmode
+		      operands[1], operands[2], VOIDmode) == CCFPmode
    && !TARGET_CMOVE"
   "#")
 
@@ -11013,7 +11013,7 @@  (define_insn "*fp_jcc_3_387"
   "X87_FLOAT_MODE_P (GET_MODE (operands[1]))
    && GET_MODE (operands[1]) == GET_MODE (operands[2])
    && SELECT_CC_MODE (GET_CODE (operands[0]),
-		      operands[1], operands[2]) == CCFPmode
+		      operands[1], operands[2], VOIDmode) == CCFPmode
    && !TARGET_CMOVE"
   "#")
 
Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c	(revision 169850)
+++ config/i386/i386.c	(working copy)
@@ -17188,7 +17188,7 @@  ix86_expand_int_compare (enum rtx_code c
   enum machine_mode cmpmode;
   rtx tmp, flags;
 
-  cmpmode = SELECT_CC_MODE (code, op0, op1);
+  cmpmode = SELECT_CC_MODE (code, op0, op1, VOIDmode);
   flags = gen_rtx_REG (cmpmode, FLAGS_REG);
 
   /* This is very simple, but making the interface the same as in the
Index: config/pdp11/pdp11.h
===================================================================
--- config/pdp11/pdp11.h	(revision 169850)
+++ config/pdp11/pdp11.h	(working copy)
@@ -500,7 +500,7 @@  extern int may_call_alloca;
    return the mode to be used for the comparison.  For floating-point, CCFPmode
    should be used.  */
 
-#define SELECT_CC_MODE(OP,X,Y)	\
+#define SELECT_CC_MODE(OP,X,Y,M)	\
 (GET_MODE_CLASS(GET_MODE(X)) == MODE_FLOAT? CCFPmode : CCmode)
 
 /* Specify the machine mode that pointers have.
Index: config/mn10300/mn10300.h
===================================================================
--- config/mn10300/mn10300.h	(revision 169850)
+++ config/mn10300/mn10300.h	(working copy)
@@ -598,7 +598,7 @@  ((GET_CODE (X) == SYMBOL_REF || GET_CODE
 /* Non-global SYMBOL_REFs have SYMBOL_REF_FLAG enabled.  */
 #define MN10300_GLOBAL_P(X) (! SYMBOL_REF_FLAG (X))
 
-#define SELECT_CC_MODE(OP, X, Y)  mn10300_select_cc_mode (OP, X, Y)
+#define SELECT_CC_MODE(OP, X, Y, M)  mn10300_select_cc_mode (OP, X, Y)
 #define REVERSIBLE_CC_MODE(MODE)  0
 
 /* Nonzero if access to memory by bytes or half words is no faster
Index: config/ia64/ia64.h
===================================================================
--- config/ia64/ia64.h	(revision 169850)
+++ config/ia64/ia64.h	(working copy)
@@ -497,7 +497,7 @@  while (0)
 
 /* We define CCImode in ia64-modes.def so we need a selector.  */
 
-#define SELECT_CC_MODE(OP,X,Y)  CCmode
+#define SELECT_CC_MODE(OP,X,Y,M)  CCmode
 
 /* Order of allocation of registers */
 
Index: config/rs6000/rs6000.h
===================================================================
--- config/rs6000/rs6000.h	(revision 169850)
+++ config/rs6000/rs6000.h	(working copy)
@@ -1920,7 +1920,7 @@  extern unsigned rs6000_pmode;
    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) \
+#define SELECT_CC_MODE(OP,X,Y,M)			\
   (SCALAR_FLOAT_MODE_P (GET_MODE (X)) ? CCFPmode	\
    : (OP) == GTU || (OP) == LTU || (OP) == GEU || (OP) == LEU ? CCUNSmode \
    : (((OP) == EQ || (OP) == NE) && COMPARISON_P (X)			  \
Index: config/arc/arc.c
===================================================================
--- config/arc/arc.c	(revision 169850)
+++ config/arc/arc.c	(working copy)
@@ -755,7 +755,7 @@  proper_comparison_operator (rtx op, enum
 rtx
 gen_compare_reg (enum rtx_code code, rtx x, rtx y)
 {
-  enum machine_mode mode = SELECT_CC_MODE (code, x, y);
+  enum machine_mode mode = SELECT_CC_MODE (code, x, y, VOIDmode);
   return gen_rtx_REG (mode, 61);
 }
 
Index: config/arc/arc.h
===================================================================
--- config/arc/arc.h	(revision 169850)
+++ config/arc/arc.h	(working copy)
@@ -654,7 +654,7 @@  (GET_CODE (X) == PLUS				\
 
 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
    return the mode to be used for the comparison.  */
-#define SELECT_CC_MODE(OP, X, Y) \
+#define SELECT_CC_MODE(OP, X, Y, M)	\
 arc_select_cc_mode (OP, X, Y)
 
 /* Return nonzero if SELECT_CC_MODE will never return MODE for a
Index: config/score/score.h
===================================================================
--- config/score/score.h	(revision 169850)
+++ config/score/score.h	(working copy)
@@ -666,7 +666,7 @@  typedef struct score_args
 #define LEGITIMATE_CONSTANT_P(X)        1
 
 /* Condition Code Status.  */
-#define SELECT_CC_MODE(OP, X, Y)        score_select_cc_mode (OP, X, Y)
+#define SELECT_CC_MODE(OP, X, Y, M)        score_select_cc_mode (OP, X, Y)
 
 /* Return nonzero if SELECT_CC_MODE will never return MODE for a
    floating point inequality comparison.  */
Index: config/arm/arm.c
===================================================================
--- config/arm/arm.c	(revision 169850)
+++ config/arm/arm.c	(working copy)
@@ -10493,9 +10493,11 @@  arm_select_dominance_cc_mode (rtx x, rtx
   /* Currently we will probably get the wrong result if the individual
      comparisons are not simple.  This also ensures that it is safe to
      reverse a comparison if necessary.  */
-  if ((arm_select_cc_mode (cond1 = GET_CODE (x), XEXP (x, 0), XEXP (x, 1))
+  if ((arm_select_cc_mode (cond1 = GET_CODE (x),
+			   XEXP (x, 0), XEXP (x, 1), VOIDmode)
        != CCmode)
-      || (arm_select_cc_mode (cond2 = GET_CODE (y), XEXP (y, 0), XEXP (y, 1))
+      || (arm_select_cc_mode (cond2 = GET_CODE (y),
+			      XEXP (y, 0), XEXP (y, 1), VOIDmode)
 	  != CCmode))
     return CCmode;
 
@@ -10627,12 +10629,15 @@  arm_select_dominance_cc_mode (rtx x, rtx
 }
 
 enum machine_mode
-arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
+arm_select_cc_mode (enum rtx_code op, rtx x, rtx y, enum machine_mode mode)
 {
   /* All floating point compares return CCFP if it is an equality
      comparison, and CCFPE otherwise.  */
   if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
     {
+      if (mode == CCFPmode || mode == CCFPEmode)
+	return mode;
+
       switch (op)
 	{
 	case EQ:
@@ -10822,7 +10827,7 @@  arm_gen_compare_reg (enum rtx_code code,
   if (dimode_comparison && !REG_P (x))
     x = force_reg (DImode, x);
 
-  mode = SELECT_CC_MODE (code, x, y);
+  mode = SELECT_CC_MODE (code, x, y, VOIDmode);
   cc_reg = gen_rtx_REG (mode, CC_REGNUM);
 
   if (dimode_comparison
@@ -17033,7 +17038,7 @@  get_arm_condition_code (rtx comparison)
 
   if (GET_MODE_CLASS (mode) != MODE_CC)
     mode = SELECT_CC_MODE (comp_code, XEXP (comparison, 0),
-			   XEXP (comparison, 1));
+			   XEXP (comparison, 1), VOIDmode);
 
   switch (mode)
     {
Index: config/arm/arm.h
===================================================================
--- config/arm/arm.h	(revision 169850)
+++ config/arm/arm.h	(working copy)
@@ -2081,7 +2081,7 @@  extern int making_const_table;
 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
    return the mode to be used for the comparison.  */
 
-#define SELECT_CC_MODE(OP, X, Y)  arm_select_cc_mode (OP, X, Y)
+#define SELECT_CC_MODE(OP, X, Y, M)  arm_select_cc_mode (OP, X, Y, M)
 
 #define REVERSIBLE_CC_MODE(MODE) 1
 
Index: config/arm/arm-protos.h
===================================================================
--- config/arm/arm-protos.h	(revision 169850)
+++ config/arm/arm-protos.h	(working copy)
@@ -106,7 +106,7 @@  extern bool gen_const_stm_seq (rtx *, in
 extern rtx arm_gen_load_multiple (int *, int, rtx, int, rtx, HOST_WIDE_INT *);
 extern rtx arm_gen_store_multiple (int *, int, rtx, int, rtx, HOST_WIDE_INT *);
 extern int arm_gen_movmemqi (rtx *);
-extern enum machine_mode arm_select_cc_mode (RTX_CODE, rtx, rtx);
+extern enum machine_mode arm_select_cc_mode (RTX_CODE, rtx, rtx, enum machine_mode);
 extern enum machine_mode arm_select_dominance_cc_mode (rtx, rtx,
 						       HOST_WIDE_INT);
 extern rtx arm_gen_compare_reg (RTX_CODE, rtx, rtx);
Index: config/arm/arm.md
===================================================================
--- config/arm/arm.md	(revision 169850)
+++ config/arm/arm.md	(working copy)
@@ -8728,7 +8728,7 @@  (define_insn_and_split "*compare_scc"
 {
   rtx tmp1;
   enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
-					   operands[2], operands[3]);
+					   operands[2], operands[3], VOIDmode);
   enum rtx_code rc = GET_CODE (operands[1]);
 
   tmp1 = gen_rtx_REG (mode, CC_REGNUM);
@@ -9118,7 +9118,8 @@  (define_insn_and_split "*and_scc_scc_nod
 			 (match_dup 0)
 			 (const_int 0)))]
   "operands[7] = gen_rtx_REG (SELECT_CC_MODE (GET_CODE (operands[6]),
-					      operands[4], operands[5]),
+					      operands[4], operands[5],
+					      VOIDmode),
 			      CC_REGNUM);
    operands[8] = gen_rtx_COMPARE (GET_MODE (operands[7]), operands[4],
 				  operands[5]);"
@@ -10064,7 +10065,8 @@  (define_split
   "
   {
     enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
-					     operands[2], operands[3]);
+					     operands[2], operands[3],
+					     VOIDmode);
     enum rtx_code rc = GET_CODE (operands[1]);
 
     operands[5] = gen_rtx_REG (mode, CC_REGNUM);
@@ -10092,7 +10094,8 @@  (define_split
   "
   {
     enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
-					     operands[2], operands[3]);
+					     operands[2], operands[3],
+					     VOIDmode);
 
     operands[5] = gen_rtx_REG (mode, CC_REGNUM);
     operands[6] = gen_rtx_COMPARE (mode, operands[2], operands[3]);
@@ -10115,7 +10118,8 @@  (define_split
   "
   {
     enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
-					     operands[2], operands[3]);
+					     operands[2], operands[3],
+					     VOIDmode);
     enum rtx_code rc = GET_CODE (operands[1]);
 
     operands[6] = gen_rtx_REG (mode, CC_REGNUM);
@@ -10147,7 +10151,8 @@  (define_split
   "
   {
     enum machine_mode mode = SELECT_CC_MODE (GET_CODE (operands[1]),
-					     operands[2], operands[3]);
+					     operands[2], operands[3],
+					     VOIDmode);
     enum rtx_code rc = GET_CODE (operands[1]);
 
     operands[6] = gen_rtx_REG (mode, CC_REGNUM);
Index: config/pa/pa.h
===================================================================
--- config/pa/pa.h	(revision 169850)
+++ config/pa/pa.h	(working copy)
@@ -1291,7 +1291,7 @@  do { 									\
    should be used.  CC_NOOVmode should be used when the first operand is a
    PLUS, MINUS, or NEG.  CCmode should be used when no special processing is
    needed.  */
-#define SELECT_CC_MODE(OP,X,Y) \
+#define SELECT_CC_MODE(OP,X,Y,M) \
   (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT ? CCFPmode : CCmode)    \
 
 /* A function address in a call instruction
Index: config/v850/v850.h
===================================================================
--- config/v850/v850.h	(revision 169850)
+++ config/v850/v850.h	(working copy)
@@ -766,7 +766,7 @@  do {									\
    For integer comparisons against zero, reduce to CCNOmode or CCZmode if
    possible, to allow for more combinations.  */
 
-#define SELECT_CC_MODE(OP, X, Y)       v850_select_cc_mode (OP, X, Y)
+#define SELECT_CC_MODE(OP, X, Y, M)       v850_select_cc_mode (OP, X, Y)
 
 /* Tell final.c how to eliminate redundant test instructions.  */
 
Index: config/mmix/mmix.h
===================================================================
--- config/mmix/mmix.h	(revision 169850)
+++ config/mmix/mmix.h	(working copy)
@@ -624,7 +624,7 @@  typedef struct { int regs; int lib; } CU
 
 /* Node: Condition Code */
 
-#define SELECT_CC_MODE(OP, X, Y)		\
+#define SELECT_CC_MODE(OP, X, Y, M)		\
  mmix_select_cc_mode (OP, X, Y)
 
 /* A definition of CANONICALIZE_COMPARISON that changed LE and GT
Index: config/mmix/mmix.c
===================================================================
--- config/mmix/mmix.c	(revision 169850)
+++ config/mmix/mmix.c	(working copy)
@@ -2468,7 +2468,7 @@  mmix_shiftable_wyde_value (unsigned HOST
 rtx
 mmix_gen_compare_reg (RTX_CODE code, rtx x, rtx y)
 {
-  enum machine_mode ccmode = SELECT_CC_MODE (code, x, y);
+  enum machine_mode ccmode = SELECT_CC_MODE (code, x, y, VOIDmode);
   return gen_reg_rtx (ccmode);
 }