i386 unordered compares

Richard Henderson rth@cygnus.com
Sun Apr 9 13:31:00 GMT 2000


In addition to simply implementing the unordered comparison operators,
I also changed rtl generation not to expand fp comparisons early.  This
in the theory that we'll get better code (especially with -mno-ieee-fp)
by giving early passes a chance to symbolicly reverse a branch compare. 
As is, they are presented with a couple bit masks, and an unspec and just
have to give up.

Bootstrapped i686-linux with -march=i586 and -march=i686, plus Plum Hall.



r~


        * genrecog.c (pred): Update comparison_operator for the unordered
        operators.

        * config/i386/i386.c (no_comparison_operator): Disallow unordered
        operators.
        (fcmov_comparison_operator): Allow UNORDERED/ORDERED.
        (uno_comparison_operator): New.
        (put_condition_code): Handle UNORDERED/ORDERED.
        (unsigned_comparison): Likewise.
        (ix86_fp_compare_mode): Broken out of ix86_expand_fp_compare.
        (ix86_use_fcomi_compare, ix86_prepare_fp_compare_args): Likewise.
        (ix86_expand_fp_compare): Use them.  Take scratch as argument,
        update all callers.  Handle all 8 unordered operators.
        (ix86_expand_setcc): Lose the unordered argument, update all callers.
        (ix86_expand_branch): Likewise.  Don't fully expand fp branches.
        * config/i386/i386.h (PREDICATE_CODES): Update.
        * config/i386/i386-protos.h (ix86_expand_fp_compare): Declare.
        (ix86_expand_branch, ix86_expand_setcc): Update.
        * config/i386/i386.md (sunordered, sordered): New.
        (suneq, sunge, sungt, sunle, sunlt, sltgt): New.
        (bunordered, bordered): New.
        (buneq, bunge, bungt, bunle, bunlt, bltgt): New.
        (*fp_jcc_1, *fp_jcc_2, *fp_jcc_3, *fp_jcc_4): New.
        (*fp_jcc_5, *fp_jcc_6, and splitters): New.

Index: genrecog.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/genrecog.c,v
retrieving revision 1.77
diff -c -p -d -r1.77 genrecog.c
*** genrecog.c	2000/04/07 07:16:59	1.77
--- genrecog.c	2000/04/09 09:24:40
*************** static struct pred_table
*** 211,217 ****
    {"pop_operand", {MEM}},
    {"memory_operand", {SUBREG, MEM}},
    {"indirect_operand", {SUBREG, MEM}},
!   {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU}},
    {"mode_independent_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
  				LABEL_REF, SUBREG, REG, MEM}}
  };
--- 211,219 ----
    {"pop_operand", {MEM}},
    {"memory_operand", {SUBREG, MEM}},
    {"indirect_operand", {SUBREG, MEM}},
!   {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU,
! 			   UNORDERED, ORDERED, UNEQ, UNGE, UNGT, UNLE,
! 			   UNLT, LTGT}},
    {"mode_independent_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
  				LABEL_REF, SUBREG, REG, MEM}}
  };
Index: config/i386/i386-protos.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386-protos.h,v
retrieving revision 1.16
diff -c -p -d -r1.16 i386-protos.h
*** i386-protos.h	2000/03/28 05:58:50	1.16
--- i386-protos.h	2000/04/09 09:24:40
*************** extern void ix86_expand_unary_operator P
*** 97,104 ****
  extern int ix86_unary_operator_ok PARAMS ((enum rtx_code, enum machine_mode,
  					 rtx[]));
  extern int ix86_match_ccmode PARAMS ((rtx, enum machine_mode));
! extern void ix86_expand_branch PARAMS ((enum rtx_code, int, rtx));
! extern int ix86_expand_setcc PARAMS ((enum rtx_code, int, rtx));
  extern int ix86_expand_int_movcc PARAMS ((rtx[]));
  extern int ix86_expand_fp_movcc PARAMS ((rtx[]));
  extern int ix86_split_long_move PARAMS ((rtx[]));
--- 97,105 ----
  extern int ix86_unary_operator_ok PARAMS ((enum rtx_code, enum machine_mode,
  					 rtx[]));
  extern int ix86_match_ccmode PARAMS ((rtx, enum machine_mode));
! extern rtx ix86_expand_fp_compare PARAMS ((enum rtx_code, rtx, rtx, rtx));
! extern void ix86_expand_branch PARAMS ((enum rtx_code, rtx));
! extern int ix86_expand_setcc PARAMS ((enum rtx_code, rtx));
  extern int ix86_expand_int_movcc PARAMS ((rtx[]));
  extern int ix86_expand_fp_movcc PARAMS ((rtx[]));
  extern int ix86_split_long_move PARAMS ((rtx[]));
Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.c,v
retrieving revision 1.152
diff -c -p -d -r1.152 i386.c
*** i386.c	2000/04/08 04:33:28	1.152
--- i386.c	2000/04/09 09:24:40
*************** static void put_condition_code PARAMS ((
*** 384,391 ****
  				       int, int, FILE *));
  static enum rtx_code unsigned_comparison PARAMS ((enum rtx_code code));
  static rtx ix86_expand_int_compare PARAMS ((enum rtx_code, rtx, rtx));
! static rtx ix86_expand_fp_compare PARAMS ((enum rtx_code, rtx, rtx, int));
! static rtx ix86_expand_compare PARAMS ((enum rtx_code, int));
  static rtx gen_push PARAMS ((rtx));
  static int memory_address_length PARAMS ((rtx addr));
  static int ix86_flags_dependant PARAMS ((rtx, rtx, enum attr_type));
--- 384,394 ----
  				       int, int, FILE *));
  static enum rtx_code unsigned_comparison PARAMS ((enum rtx_code code));
  static rtx ix86_expand_int_compare PARAMS ((enum rtx_code, rtx, rtx));
! static enum machine_mode ix86_fp_compare_mode PARAMS ((enum rtx_code));
! static int ix86_use_fcomi_compare PARAMS ((enum rtx_code));
! static enum rtx_code ix86_prepare_fp_compare_args PARAMS ((enum rtx_code,
! 							   rtx *, rtx *));
! static rtx ix86_expand_compare PARAMS ((enum rtx_code));
  static rtx gen_push PARAMS ((rtx));
  static int memory_address_length PARAMS ((rtx addr));
  static int ix86_flags_dependant PARAMS ((rtx, rtx, enum attr_type));
*************** no_comparison_operator (op, mode)
*** 1235,1244 ****
      register rtx op;
      enum machine_mode mode;
  {
!   return ((mode == VOIDmode || GET_MODE (op) == mode)
! 	  && GET_RTX_CLASS (GET_CODE (op)) == '<'
! 	  && GET_CODE (op) != LE
! 	  && GET_CODE (op) != GT);
  }
  
  /* Return 1 if OP is a comparison operator that can be issued by fcmov.  */
--- 1238,1256 ----
      register rtx op;
      enum machine_mode mode;
  {
!   if (mode != VOIDmode && GET_MODE (op) != mode)
!     return 0;
! 
!   switch (GET_CODE (op))
!     {
!     case EQ: case NE:
!     case LT: case GE:
!     case LEU: case LTU: case GEU: case GTU:
!       return 1;
! 
!     default:
!       return 0;
!     }
  }
  
  /* Return 1 if OP is a comparison operator that can be issued by fcmov.  */
*************** fcmov_comparison_operator (op, mode)
*** 1248,1256 ****
      register rtx op;
      enum machine_mode mode;
  {
!   return ((mode == VOIDmode || GET_MODE (op) == mode)
! 	  && GET_RTX_CLASS (GET_CODE (op)) == '<'
! 	  && GET_CODE (op) == unsigned_condition (GET_CODE (op)));
  }
  
  /* Return 1 if OP is a binary operator that can be promoted to wider mode.  */
--- 1260,1301 ----
      register rtx op;
      enum machine_mode mode;
  {
!   if (mode != VOIDmode && GET_MODE (op) != mode)
!     return 0;
! 
!   switch (GET_CODE (op))
!     {
!     case EQ: case NE:
!     case LEU: case LTU: case GEU: case GTU:
!     case UNORDERED: case ORDERED:
!       return 1;
! 
!     default:
!       return 0;
!     }
! }
! 
! /* Return 1 if OP is any normal comparison operator plus {UN}ORDERED.  */
! 
! int 
! uno_comparison_operator (op, mode)
!     register rtx op;
!     enum machine_mode mode;
! {
!   if (mode != VOIDmode && GET_MODE (op) != mode)
!     return 0;
! 
!   switch (GET_CODE (op))
!     {
!     case EQ: case NE:
!     case LE: case LT: case GE: case GT:
!     case LEU: case LTU: case GEU: case GTU:
!     case UNORDERED: case ORDERED:
!       return 1;
! 
!     default:
!       return 0;
!     }
  }
  
  /* Return 1 if OP is a binary operator that can be promoted to wider mode.  */
*************** put_condition_code (code, mode, reverse,
*** 2970,2975 ****
--- 3015,3026 ----
      case LEU:
        suffix = "be";
        break;
+     case UNORDERED:
+       suffix = "p";
+       break;
+     case ORDERED:
+       suffix = "np";
+       break;
      default:
        abort ();
      }
*************** unsigned_comparison (code)
*** 4384,4389 ****
--- 4435,4442 ----
      case LTU:
      case GEU:
      case GTU:
+     case UNORDERED:
+     case ORDERED:
        break;
      default:
        abort ();
*************** ix86_expand_int_compare (code, op0, op1)
*** 4414,4449 ****
    return gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
  }
  
! /* Generate insn patterns to do a floating point compare of OPERANDS.
!    If UNORDERED, allow for unordered compares.  */
  
! static rtx
! ix86_expand_fp_compare (code, op0, op1, unordered)
       enum rtx_code code;
-      rtx op0, op1;
-      int unordered;
  {
!   enum machine_mode fpcmp_mode;
!   enum machine_mode intcmp_mode;
!   rtx tmp;
  
!   /* When not doing IEEE compliant compares, disable unordered.  */
!   if (! TARGET_IEEE_FP)
!     unordered = 0;
!   fpcmp_mode = unordered ? CCFPUmode : CCFPmode;
  
    /* ??? If we knew whether invalid-operand exceptions were masked,
       we could rely on fcom to raise an exception and take care of
!      NaNs.  But we don't.  We could know this from c9x math bits.  */
    if (TARGET_IEEE_FP)
      unordered = 1;
  
    /* All of the unordered compare instructions only work on registers.
!      The same is true of the XFmode compare instructions.  */
!   if (unordered || GET_MODE (op0) == XFmode)
      {
!       op0 = force_reg (GET_MODE (op0), op0);
!       op1 = force_reg (GET_MODE (op1), op1);
      }
    else
      {
--- 4467,4546 ----
    return gen_rtx_fmt_ee (code, VOIDmode, flags, const0_rtx);
  }
  
! /* Figure out whether to use ordered or unordered fp comparisons.
!    Return the appropriate mode to use.  */
  
! static enum machine_mode
! ix86_fp_compare_mode (code)
       enum rtx_code code;
  {
!   int unordered;
  
!   switch (code)
!     {
!     case NE: case EQ:
!       /* When not doing IEEE compliant compares, fault on NaNs.  */
!       unordered = (TARGET_IEEE_FP != 0);
!       break;
! 
!     case LT: case LE: case GT: case GE:
!       unordered = 0;
!       break;
! 
!     case UNORDERED: case ORDERED:
!     case UNEQ: case UNGE: case UNGT: case UNLE: case UNLT: case LTGT:
!       unordered = 1;
!       break;
! 
!     default:
!       abort ();
!     }
  
    /* ??? If we knew whether invalid-operand exceptions were masked,
       we could rely on fcom to raise an exception and take care of
!      NaNs.  But we don't.  We could know this from c99 math pragmas.  */
    if (TARGET_IEEE_FP)
      unordered = 1;
  
+   return unordered ? CCFPUmode : CCFPmode;
+ }
+ 
+ /* Return true if we should use an FCOMI instruction for this fp comparison.  */
+ 
+ static int
+ ix86_use_fcomi_compare (code)
+      enum rtx_code code;
+ {
+   return (TARGET_CMOVE
+ 	  && (code == ORDERED || code == UNORDERED
+ 	      /* All other unordered compares require checking
+ 		 multiple sets of bits.  */
+ 	      || ix86_fp_compare_mode (code) == CCFPmode));
+ }
+ 
+ /* Swap, force into registers, or otherwise massage the two operands 
+    to a fp comparison.  The operands are updated in place; the new
+    comparsion code is returned.  */
+ 
+ static enum rtx_code
+ ix86_prepare_fp_compare_args (code, pop0, pop1)
+      enum rtx_code code;
+      rtx *pop0, *pop1;
+ {
+   enum machine_mode fpcmp_mode = ix86_fp_compare_mode (code);
+   rtx op0 = *pop0, op1 = *pop1;
+   enum machine_mode op_mode = GET_MODE (op0);
+ 
    /* All of the unordered compare instructions only work on registers.
!      The same is true of the XFmode compare instructions.  The same is
!      true of the fcomi compare instructions.  */
! 
!   if (fpcmp_mode == CCFPUmode
!       || op_mode == XFmode
!       || ix86_use_fcomi_compare (code))
      {
!       op0 = force_reg (op_mode, op0);
!       op1 = force_reg (op_mode, op1);
      }
    else
      {
*************** ix86_expand_fp_compare (code, op0, op1, 
*** 4462,4494 ****
  	}
  
        if (GET_CODE (op0) != REG)
! 	op0 = force_reg (GET_MODE (op0), op0);
  
        if (CONSTANT_P (op1))
  	{
  	  if (standard_80387_constant_p (op1))
! 	    op1 = force_reg (GET_MODE (op1), op1);
  	  else
! 	    op1 = validize_mem (force_const_mem (GET_MODE (op1), op1));
  	}
      }
  
    /* %%% fcomi is probably always faster, even when dealing with memory,
       since compare-and-branch would be three insns instead of four.  */
!   if (TARGET_CMOVE && !unordered)
      {
-       if (GET_CODE (op0) != REG)
- 	op0 = force_reg (GET_MODE (op0), op0);
-       if (GET_CODE (op1) != REG)
- 	op1 = force_reg (GET_MODE (op1), op1);
- 
        tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
        tmp = gen_rtx_SET (VOIDmode, gen_rtx_REG (fpcmp_mode, FLAGS_REG), tmp);
        emit_insn (tmp);
  
        /* The FP codes work out to act like unsigned.  */
        code = unsigned_comparison (code);
!       intcmp_mode = fpcmp_mode;
      }
    else
      {
--- 4559,4604 ----
  	}
  
        if (GET_CODE (op0) != REG)
! 	op0 = force_reg (op_mode, op0);
  
        if (CONSTANT_P (op1))
  	{
  	  if (standard_80387_constant_p (op1))
! 	    op1 = force_reg (op_mode, op1);
  	  else
! 	    op1 = validize_mem (force_const_mem (op_mode, op1));
  	}
      }
  
+   *pop0 = op0;
+   *pop1 = op1;
+   return code;
+ }
+ 
+ /* Generate insn patterns to do a floating point compare of OPERANDS.  */
+ 
+ rtx
+ ix86_expand_fp_compare (code, op0, op1, scratch)
+      enum rtx_code code;
+      rtx op0, op1, scratch;
+ {
+   enum machine_mode fpcmp_mode, intcmp_mode;
+   rtx tmp;
+ 
+   fpcmp_mode = ix86_fp_compare_mode (code);
+   code = ix86_prepare_fp_compare_args (code, &op0, &op1);
+ 
    /* %%% fcomi is probably always faster, even when dealing with memory,
       since compare-and-branch would be three insns instead of four.  */
!   if (ix86_use_fcomi_compare (code))
      {
        tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
        tmp = gen_rtx_SET (VOIDmode, gen_rtx_REG (fpcmp_mode, FLAGS_REG), tmp);
        emit_insn (tmp);
  
        /* The FP codes work out to act like unsigned.  */
        code = unsigned_comparison (code);
!       intcmp_mode = CCmode;
      }
    else
      {
*************** ix86_expand_fp_compare (code, op0, op1, 
*** 4497,4506 ****
        rtx tmp2;
        tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
        tmp2 = gen_rtx_UNSPEC (HImode, gen_rtvec (1, tmp), 9);
!       tmp = gen_reg_rtx (HImode);
!       emit_insn (gen_rtx_SET (VOIDmode, tmp, tmp2));
  
!       if (! unordered)
  	{
  	  /* We have two options here -- use sahf, or testing bits of ah
  	     directly.  On PPRO, they are equivalent, sahf being one byte
--- 4607,4617 ----
        rtx tmp2;
        tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
        tmp2 = gen_rtx_UNSPEC (HImode, gen_rtvec (1, tmp), 9);
!       emit_insn (gen_rtx_SET (VOIDmode, scratch, tmp2));
  
!       if (fpcmp_mode == CCFPmode
! 	  || code == ORDERED
! 	  || code == UNORDERED)
  	{
  	  /* We have two options here -- use sahf, or testing bits of ah
  	     directly.  On PPRO, they are equivalent, sahf being one byte
*************** ix86_expand_fp_compare (code, op0, op1, 
*** 4510,4519 ****
  	  if (TARGET_USE_SAHF || optimize_size)
  	    {
  	    do_sahf:
  
  	      /* The FP codes work out to act like unsigned.  */
  	      code = unsigned_comparison (code);
- 	      emit_insn (gen_x86_sahf_1 (tmp));
  	      intcmp_mode = CCmode;
  	    }
  	  else
--- 4621,4630 ----
  	  if (TARGET_USE_SAHF || optimize_size)
  	    {
  	    do_sahf:
+ 	      emit_insn (gen_x86_sahf_1 (scratch));
  
  	      /* The FP codes work out to act like unsigned.  */
  	      code = unsigned_comparison (code);
  	      intcmp_mode = CCmode;
  	    }
  	  else
*************** ix86_expand_fp_compare (code, op0, op1, 
*** 4557,4567 ****
  		  mask = 0x40;
  		  code = EQ;
  		  break;
  		default:
  		  abort ();
  		}
  
! 	      emit_insn (gen_testqi_ext_ccno_0 (tmp, GEN_INT (mask)));
  	      intcmp_mode = CCNOmode;
  	    }
  	}
--- 4668,4687 ----
  		  mask = 0x40;
  		  code = EQ;
  		  break;
+ 		case UNORDERED:
+ 		  mask = 0x04;
+ 		  code = NE;
+ 		  break;
+ 		case ORDERED:
+ 		  mask = 0x04;
+ 		  code = EQ;
+ 		  break;
+ 
  		default:
  		  abort ();
  		}
  
! 	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (mask)));
  	      intcmp_mode = CCNOmode;
  	    }
  	}
*************** ix86_expand_fp_compare (code, op0, op1, 
*** 4576,4612 ****
  	  switch (code)
  	    {
  	    case GT:
! 	      emit_insn (gen_testqi_ext_ccno_0 (tmp, GEN_INT (0x45)));
  	      code = EQ;
  	      break;
  	    case LT:
! 	      emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45)));
! 	      emit_insn (gen_cmpqi_ext_3 (tmp, GEN_INT (0x01)));
  	      intcmp_mode = CCmode;
  	      code = EQ;
  	      break;
  	    case GE:
! 	      emit_insn (gen_testqi_ext_ccno_0 (tmp, GEN_INT (0x05)));
  	      code = EQ;
  	      break;
  	    case LE:
! 	      emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45)));
! 	      emit_insn (gen_addqi_ext_1 (tmp, tmp, constm1_rtx));
! 	      emit_insn (gen_cmpqi_ext_3 (tmp, GEN_INT (0x40)));
  	      intcmp_mode = CCmode;
  	      code = LTU;
  	      break;
  	    case EQ:
! 	      emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45)));
! 	      emit_insn (gen_cmpqi_ext_3 (tmp, GEN_INT (0x40)));
  	      intcmp_mode = CCmode;
  	      code = EQ;
  	      break;
  	    case NE:
! 	      emit_insn (gen_andqi_ext_0 (tmp, tmp, GEN_INT (0x45)));
! 	      emit_insn (gen_xorqi_cc_ext_1 (tmp, tmp, GEN_INT (0x40)));
  	      code = NE;
  	      break;
  	    default:
  	      abort ();
  	    }
--- 4696,4769 ----
  	  switch (code)
  	    {
  	    case GT:
! 	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x45)));
  	      code = EQ;
  	      break;
  	    case LT:
! 	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
! 	      emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x01)));
  	      intcmp_mode = CCmode;
  	      code = EQ;
  	      break;
  	    case GE:
! 	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x05)));
  	      code = EQ;
  	      break;
  	    case LE:
! 	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
! 	      emit_insn (gen_addqi_ext_1 (scratch, scratch, constm1_rtx));
! 	      emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x40)));
  	      intcmp_mode = CCmode;
  	      code = LTU;
  	      break;
  	    case EQ:
! 	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
! 	      emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x40)));
  	      intcmp_mode = CCmode;
  	      code = EQ;
  	      break;
  	    case NE:
! 	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
! 	      emit_insn (gen_xorqi_cc_ext_1 (scratch, scratch, GEN_INT (0x40)));
! 	      code = NE;
! 	      break;
! 
! 	    case UNORDERED:
! 	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x04)));
! 	      code = NE;
! 	      break;
! 	    case ORDERED:
! 	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x04)));
! 	      code = EQ;
! 	      break;
! 	    case UNEQ:
! 	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x40)));
! 	      code = NE;
! 	      break;
! 	    case UNGE:
! 	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
! 	      emit_insn (gen_xorqi_cc_ext_1 (scratch, scratch, GEN_INT (0x01)));
! 	      code = NE;
! 	      break;
! 	    case UNGT:
! 	      emit_insn (gen_andqi_ext_0 (scratch, scratch, GEN_INT (0x45)));
! 	      emit_insn (gen_addqi_ext_1 (scratch, scratch, constm1_rtx));
! 	      emit_insn (gen_cmpqi_ext_3 (scratch, GEN_INT (0x44)));
! 	      code = GEU;
! 	      break;
! 	    case UNLE:
! 	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x45)));
! 	      code = NE;
! 	      break;
! 	    case UNLT:
! 	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x01)));
  	      code = NE;
  	      break;
+ 	    case LTGT:
+ 	      emit_insn (gen_testqi_ext_ccno_0 (scratch, GEN_INT (0x40)));
+ 	      code = EQ;
+ 	      break;
+ 
  	    default:
  	      abort ();
  	    }
*************** ix86_expand_fp_compare (code, op0, op1, 
*** 4621,4636 ****
  }
  
  static rtx
! ix86_expand_compare (code, unordered)
       enum rtx_code code;
-      int unordered;
  {
    rtx op0, op1, ret;
    op0 = ix86_compare_op0;
    op1 = ix86_compare_op1;
  
    if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
!     ret = ix86_expand_fp_compare (code, op0, op1, unordered);
    else
      ret = ix86_expand_int_compare (code, op0, op1);
  
--- 4778,4792 ----
  }
  
  static rtx
! ix86_expand_compare (code)
       enum rtx_code code;
  {
    rtx op0, op1, ret;
    op0 = ix86_compare_op0;
    op1 = ix86_compare_op1;
  
    if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
!     ret = ix86_expand_fp_compare (code, op0, op1, gen_reg_rtx (HImode));
    else
      ret = ix86_expand_int_compare (code, op0, op1);
  
*************** ix86_expand_compare (code, unordered)
*** 4638,4771 ****
  }
  
  void
! ix86_expand_branch (code, unordered, label)
       enum rtx_code code;
-      int unordered;
       rtx label;
  {
!   rtx tmp, lo[2], hi[2], label2;
!   enum rtx_code code1, code2, code3;
  
!   if (GET_MODE (ix86_compare_op0) != DImode)
      {
!       tmp = ix86_expand_compare (code, unordered);
        tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
  				  gen_rtx_LABEL_REF (VOIDmode, label),
  				  pc_rtx);
        emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
        return;
-     }
  
!   /* Expand DImode branch into multiple compare+branch.  */
  
!   if (CONSTANT_P (ix86_compare_op0) && ! CONSTANT_P (ix86_compare_op1))
!     {
!       tmp = ix86_compare_op0;
!       ix86_compare_op0 = ix86_compare_op1;
!       ix86_compare_op1 = tmp;
!       code = swap_condition (code);
!     }
!   split_di (&ix86_compare_op0, 1, lo+0, hi+0);
!   split_di (&ix86_compare_op1, 1, lo+1, hi+1);
  
!   /* When comparing for equality, we can use (hi0^hi1)|(lo0^lo1) to avoid
!      two branches.  This costs one extra insn, so disable when optimizing
!      for size.  */
  
!   if ((code == EQ || code == NE)
!       && (!optimize_size
! 	  || hi[1] == const0_rtx || lo[1] == const0_rtx))
!     {
!       rtx xor0, xor1;
  
!       xor1 = hi[0];
!       if (hi[1] != const0_rtx)
! 	{
! 	  xor1 = expand_binop (SImode, xor_optab, xor1, hi[1],
! 			       NULL_RTX, 0, OPTAB_WIDEN);
! 	}
  
!       xor0 = lo[0];
!       if (lo[1] != const0_rtx)
! 	{
! 	  xor0 = expand_binop (SImode, xor_optab, xor0, lo[1],
! 			       NULL_RTX, 0, OPTAB_WIDEN);
! 	}
  
!       tmp = expand_binop (SImode, ior_optab, xor1, xor0,
! 			  NULL_RTX, 0, OPTAB_WIDEN);
  
!       ix86_compare_op0 = tmp;
!       ix86_compare_op1 = const0_rtx;
!       ix86_expand_branch (code, unordered, label);
!       return;
!     }
  
!   /* Otherwise, if we are doing less-than, op1 is a constant and the
!      low word is zero, then we can just examine the high word.  */
  
!   if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
!       && (code == LT || code == LTU))
!     {
!       ix86_compare_op0 = hi[0];
!       ix86_compare_op1 = hi[1];
!       ix86_expand_branch (code, unordered, label);
!       return;
!     }
  
!   /* Otherwise, we need two or three jumps.  */
  
!   label2 = gen_label_rtx ();
  
!   code1 = code;
!   code2 = swap_condition (code);
!   code3 = unsigned_condition (code);
  
!   switch (code)
!     {
!     case LT: case GT: case LTU: case GTU:
!       break;
  
!     case LE:   code1 = LT;  code2 = GT;  break;
!     case GE:   code1 = GT;  code2 = LT;  break;
!     case LEU:  code1 = LTU; code2 = GTU; break;
!     case GEU:  code1 = GTU; code2 = LTU; break;
  
!     case EQ:   code1 = NIL; code2 = NE;  break;
!     case NE:   code2 = NIL; break;
  
!     default:
!       abort ();
!     }
  
!   /*
!    * a < b =>
!    *    if (hi(a) < hi(b)) goto true;
!    *    if (hi(a) > hi(b)) goto false;
!    *    if (lo(a) < lo(b)) goto true;
!    *  false:
!    */
  
!   ix86_compare_op0 = hi[0];
!   ix86_compare_op1 = hi[1];
  
!   if (code1 != NIL)
!     ix86_expand_branch (code1, unordered, label);
!   if (code2 != NIL)
!     ix86_expand_branch (code2, unordered, label2);
  
!   ix86_compare_op0 = lo[0];
!   ix86_compare_op1 = lo[1];
!   ix86_expand_branch (code3, unordered, label);
  
!   if (code2 != NIL)
!     emit_label (label2);
  }
  
  int
! ix86_expand_setcc (code, unordered, dest)
       enum rtx_code code;
-      int unordered;
       rtx dest;
  {
    rtx ret, tmp;
--- 4794,4966 ----
  }
  
  void
! ix86_expand_branch (code, label)
       enum rtx_code code;
       rtx label;
  {
!   rtx tmp;
  
!   switch (GET_MODE (ix86_compare_op0))
      {
!     case QImode:
!     case HImode:
!     case SImode:
!       tmp = ix86_expand_compare (code);
        tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
  				  gen_rtx_LABEL_REF (VOIDmode, label),
  				  pc_rtx);
        emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
        return;
  
!     case SFmode:
!     case DFmode:
!     case XFmode:   
!       /* Don't expand the comparison early, so that we get better code
! 	 when jump or whoever decides to reverse the comparison.  */
!       {
! 	rtvec vec;
! 	int use_fcomi;
  
! 	code = ix86_prepare_fp_compare_args (code, &ix86_compare_op0,
! 					     &ix86_compare_op1);
  
! 	tmp = gen_rtx_fmt_ee (code, ix86_fp_compare_mode (code),
! 			      ix86_compare_op0, ix86_compare_op1);
! 	tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
! 				    gen_rtx_LABEL_REF (VOIDmode, label),
! 				    pc_rtx);
! 	tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
  
! 	use_fcomi = ix86_use_fcomi_compare (code);
! 	vec = rtvec_alloc (3 + !use_fcomi);
! 	RTVEC_ELT (vec, 0) = tmp;
! 	RTVEC_ELT (vec, 1)
! 	  = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
! 	RTVEC_ELT (vec, 2)
! 	  = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
! 	if (! use_fcomi)
! 	  RTVEC_ELT (vec, 3)
! 	    = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
  
!         emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
! 	return;
!       }
  
!     case DImode:
!       /* Expand DImode branch into multiple compare+branch.  */
!       {
! 	rtx lo[2], hi[2], label2;
! 	enum rtx_code code1, code2, code3;
  
! 	if (CONSTANT_P (ix86_compare_op0) && ! CONSTANT_P (ix86_compare_op1))
! 	  {
! 	    tmp = ix86_compare_op0;
! 	    ix86_compare_op0 = ix86_compare_op1;
! 	    ix86_compare_op1 = tmp;
! 	    code = swap_condition (code);
! 	  }
! 	split_di (&ix86_compare_op0, 1, lo+0, hi+0);
! 	split_di (&ix86_compare_op1, 1, lo+1, hi+1);
  
! 	/* When comparing for equality, we can use (hi0^hi1)|(lo0^lo1) to
! 	   avoid two branches.  This costs one extra insn, so disable when
! 	   optimizing for size.  */
  
! 	if ((code == EQ || code == NE)
! 	    && (!optimize_size
! 	        || hi[1] == const0_rtx || lo[1] == const0_rtx))
! 	  {
! 	    rtx xor0, xor1;
  
! 	    xor1 = hi[0];
! 	    if (hi[1] != const0_rtx)
! 	      xor1 = expand_binop (SImode, xor_optab, xor1, hi[1],
! 				   NULL_RTX, 0, OPTAB_WIDEN);
  
! 	    xor0 = lo[0];
! 	    if (lo[1] != const0_rtx)
! 	      xor0 = expand_binop (SImode, xor_optab, xor0, lo[1],
! 				   NULL_RTX, 0, OPTAB_WIDEN);
  
! 	    tmp = expand_binop (SImode, ior_optab, xor1, xor0,
! 				NULL_RTX, 0, OPTAB_WIDEN);
  
! 	    ix86_compare_op0 = tmp;
! 	    ix86_compare_op1 = const0_rtx;
! 	    ix86_expand_branch (code, label);
! 	    return;
! 	  }
  
! 	/* Otherwise, if we are doing less-than, op1 is a constant and the
! 	   low word is zero, then we can just examine the high word.  */
  
! 	if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
! 	    && (code == LT || code == LTU))
! 	  {
! 	    ix86_compare_op0 = hi[0];
! 	    ix86_compare_op1 = hi[1];
! 	    ix86_expand_branch (code, label);
! 	    return;
! 	  }
  
! 	/* Otherwise, we need two or three jumps.  */
  
! 	label2 = gen_label_rtx ();
  
! 	code1 = code;
! 	code2 = swap_condition (code);
! 	code3 = unsigned_condition (code);
  
! 	switch (code)
! 	  {
! 	  case LT: case GT: case LTU: case GTU:
! 	    break;
  
! 	  case LE:   code1 = LT;  code2 = GT;  break;
! 	  case GE:   code1 = GT;  code2 = LT;  break;
! 	  case LEU:  code1 = LTU; code2 = GTU; break;
! 	  case GEU:  code1 = GTU; code2 = LTU; break;
  
! 	  case EQ:   code1 = NIL; code2 = NE;  break;
! 	  case NE:   code2 = NIL; break;
  
! 	  default:
! 	    abort ();
! 	  }
! 
! 	/*
! 	 * a < b =>
! 	 *    if (hi(a) < hi(b)) goto true;
! 	 *    if (hi(a) > hi(b)) goto false;
! 	 *    if (lo(a) < lo(b)) goto true;
! 	 *  false:
! 	 */
! 
! 	ix86_compare_op0 = hi[0];
! 	ix86_compare_op1 = hi[1];
! 
! 	if (code1 != NIL)
! 	  ix86_expand_branch (code1, label);
! 	if (code2 != NIL)
! 	  ix86_expand_branch (code2, label2);
! 
! 	ix86_compare_op0 = lo[0];
! 	ix86_compare_op1 = lo[1];
! 	ix86_expand_branch (code3, label);
! 
! 	if (code2 != NIL)
! 	  emit_label (label2);
! 	return;
!       }
! 
!     default:
!       abort ();
!     }
  }
  
  int
! ix86_expand_setcc (code, dest)
       enum rtx_code code;
       rtx dest;
  {
    rtx ret, tmp;
*************** ix86_expand_setcc (code, unordered, dest
*** 4794,4800 ****
    if (type == 0)
      emit_move_insn (dest, const0_rtx);
  
!   ret = ix86_expand_compare (code, unordered);
    PUT_MODE (ret, QImode);
  
    tmp = dest;
--- 4989,4995 ----
    if (type == 0)
      emit_move_insn (dest, const0_rtx);
  
!   ret = ix86_expand_compare (code);
    PUT_MODE (ret, QImode);
  
    tmp = dest;
*************** ix86_expand_int_movcc (operands)
*** 4851,4858 ****
  	code = GEU;
        ix86_compare_op1 = GEN_INT (INTVAL (ix86_compare_op1) + 1);
      }
    start_sequence ();
!   compare_op = ix86_expand_compare (code, code == EQ || code == NE);
    compare_seq = gen_sequence ();
    end_sequence ();
  
--- 5046,5054 ----
  	code = GEU;
        ix86_compare_op1 = GEN_INT (INTVAL (ix86_compare_op1) + 1);
      }
+ 
    start_sequence ();
!   compare_op = ix86_expand_compare (code);
    compare_seq = gen_sequence ();
    end_sequence ();
  
*************** ix86_expand_fp_movcc (operands)
*** 5163,5169 ****
      case GE:
      case GT:
        tmp = gen_reg_rtx (QImode);
!       ix86_expand_setcc (code, 0, tmp);
        code = NE;
        ix86_compare_op0 = tmp;
        ix86_compare_op1 = const0_rtx;
--- 5359,5365 ----
      case GE:
      case GT:
        tmp = gen_reg_rtx (QImode);
!       ix86_expand_setcc (code, tmp);
        code = NE;
        ix86_compare_op0 = tmp;
        ix86_compare_op1 = const0_rtx;
Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.h,v
retrieving revision 1.109
diff -c -p -d -r1.109 i386.h
*** i386.h	2000/04/03 23:25:06	1.109
--- i386.h	2000/04/09 09:24:40
*************** do { long l;						\
*** 2508,2513 ****
--- 2508,2515 ----
    {"non_q_regs_operand", {SUBREG, REG}},				\
    {"no_comparison_operator", {EQ, NE, LT, GE, LTU, GTU, LEU, GEU}},	\
    {"fcmov_comparison_operator", {EQ, NE, LTU, GTU, LEU, GEU}},		\
+   {"uno_comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU,	\
+ 			       GTU, UNORDERED, ORDERED}},		\
    {"cmp_fp_expander_operand", {CONST_DOUBLE, SUBREG, REG, MEM}},	\
    {"ext_register_operand", {SUBREG, REG}},				\
    {"binary_fp_operator", {PLUS, MINUS, MULT, DIV}},			\
Index: config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.md,v
retrieving revision 1.149
diff -c -p -d -r1.149 i386.md
*** i386.md	2000/04/08 04:33:28	1.149
--- i386.md	2000/04/09 09:24:41
***************
*** 6549,6610 ****
    [(set (match_operand:SI 0 "register_operand" "")
          (eq:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (EQ, 1, operands[0])) DONE; else FAIL;")
  
  (define_expand "sne"
    [(set (match_operand:SI 0 "register_operand" "")
          (ne:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (NE, 1, operands[0])) DONE; else FAIL;")
  
  (define_expand "sgt"
    [(set (match_operand:SI 0 "register_operand" "")
          (gt:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (GT, 0, operands[0])) DONE; else FAIL;")
  
  (define_expand "sgtu"
    [(set (match_operand:SI 0 "register_operand" "")
          (gtu:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (GTU, 0, operands[0])) DONE; else FAIL;")
  
  (define_expand "slt"
    [(set (match_operand:SI 0 "register_operand" "")
          (lt:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (LT, 0, operands[0])) DONE; else FAIL;")
  
  (define_expand "sltu"
    [(set (match_operand:SI 0 "register_operand" "")
          (ltu:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (LTU, 0, operands[0])) DONE; else FAIL;")
  
  (define_expand "sge"
    [(set (match_operand:SI 0 "register_operand" "")
          (ge:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (GE, 0, operands[0])) DONE; else FAIL;")
  
  (define_expand "sgeu"
    [(set (match_operand:SI 0 "register_operand" "")
          (geu:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (GEU, 0, operands[0])) DONE; else FAIL;")
  
  (define_expand "sle"
    [(set (match_operand:SI 0 "register_operand" "")
          (le:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (LE, 0, operands[0])) DONE; else FAIL;")
  
  (define_expand "sleu"
    [(set (match_operand:SI 0 "register_operand" "")
          (leu:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (LEU, 0, operands[0])) DONE; else FAIL;")
  
  (define_insn "*setcc_1"
    [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
  	(match_operator:QI 1 "no_comparison_operator"
--- 6549,6658 ----
    [(set (match_operand:SI 0 "register_operand" "")
          (eq:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (EQ, operands[0])) DONE; else FAIL;")
  
  (define_expand "sne"
    [(set (match_operand:SI 0 "register_operand" "")
          (ne:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (NE, operands[0])) DONE; else FAIL;")
  
  (define_expand "sgt"
    [(set (match_operand:SI 0 "register_operand" "")
          (gt:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (GT, operands[0])) DONE; else FAIL;")
  
  (define_expand "sgtu"
    [(set (match_operand:SI 0 "register_operand" "")
          (gtu:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (GTU, operands[0])) DONE; else FAIL;")
  
  (define_expand "slt"
    [(set (match_operand:SI 0 "register_operand" "")
          (lt:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (LT, operands[0])) DONE; else FAIL;")
  
  (define_expand "sltu"
    [(set (match_operand:SI 0 "register_operand" "")
          (ltu:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (LTU, operands[0])) DONE; else FAIL;")
  
  (define_expand "sge"
    [(set (match_operand:SI 0 "register_operand" "")
          (ge:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (GE, operands[0])) DONE; else FAIL;")
  
  (define_expand "sgeu"
    [(set (match_operand:SI 0 "register_operand" "")
          (geu:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (GEU, operands[0])) DONE; else FAIL;")
  
  (define_expand "sle"
    [(set (match_operand:SI 0 "register_operand" "")
          (le:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (LE, operands[0])) DONE; else FAIL;")
  
  (define_expand "sleu"
    [(set (match_operand:SI 0 "register_operand" "")
          (leu:SI (reg:CC 17) (const_int 0)))]
    ""
!   "if (ix86_expand_setcc (LEU, operands[0])) DONE; else FAIL;")
! 
! (define_expand "sunordered"
!   [(set (match_operand:SI 0 "register_operand" "")
!         (unordered:SI (reg:CC 17) (const_int 0)))]
!   "TARGET_80387"
!   "if (ix86_expand_setcc (UNORDERED, operands[0])) DONE; else FAIL;")
! 
! (define_expand "sordered"
!   [(set (match_operand:SI 0 "register_operand" "")
!         (ordered:SI (reg:CC 17) (const_int 0)))]
!   "TARGET_80387"
!   "if (ix86_expand_setcc (ORDERED, operands[0])) DONE; else FAIL;")
! 
! (define_expand "suneq"
!   [(set (match_operand:SI 0 "register_operand" "")
!         (uneq:SI (reg:CC 17) (const_int 0)))]
!   "TARGET_80387"
!   "if (ix86_expand_setcc (UNEQ, operands[0])) DONE; else FAIL;")
  
+ (define_expand "sunge"
+   [(set (match_operand:SI 0 "register_operand" "")
+         (unge:SI (reg:CC 17) (const_int 0)))]
+   "TARGET_80387"
+   "if (ix86_expand_setcc (UNGE, operands[0])) DONE; else FAIL;")
+ 
+ (define_expand "sungt"
+   [(set (match_operand:SI 0 "register_operand" "")
+         (ungt:SI (reg:CC 17) (const_int 0)))]
+   "TARGET_80387"
+   "if (ix86_expand_setcc (UNGT, operands[0])) DONE; else FAIL;")
+ 
+ (define_expand "sunle"
+   [(set (match_operand:SI 0 "register_operand" "")
+         (unle:SI (reg:CC 17) (const_int 0)))]
+   "TARGET_80387"
+   "if (ix86_expand_setcc (UNLE, operands[0])) DONE; else FAIL;")
+ 
+ (define_expand "sunlt"
+   [(set (match_operand:SI 0 "register_operand" "")
+         (unlt:SI (reg:CC 17) (const_int 0)))]
+   "TARGET_80387"
+   "if (ix86_expand_setcc (UNLT, operands[0])) DONE; else FAIL;")
+ 
+ (define_expand "sltgt"
+   [(set (match_operand:SI 0 "register_operand" "")
+         (ltgt:SI (reg:CC 17) (const_int 0)))]
+   "TARGET_80387"
+   "if (ix86_expand_setcc (LTGT, operands[0])) DONE; else FAIL;")
+ 
  (define_insn "*setcc_1"
    [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
  	(match_operator:QI 1 "no_comparison_operator"
***************
*** 6623,6629 ****
  
  (define_insn "*setcc_3"
    [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
! 	(match_operator:QI 1 "comparison_operator"
  	  [(reg:CC 17) (const_int 0)]))]
    ""
    "set%C1\\t%0"
--- 6671,6677 ----
  
  (define_insn "*setcc_3"
    [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
! 	(match_operator:QI 1 "uno_comparison_operator"
  	  [(reg:CC 17) (const_int 0)]))]
    ""
    "set%C1\\t%0"
***************
*** 6631,6637 ****
  
  (define_insn "*setcc_4"
    [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm"))
! 	(match_operator:QI 1 "comparison_operator"
  	  [(reg:CC 17) (const_int 0)]))]
    ""
    "set%C1\\t%0"
--- 6679,6685 ----
  
  (define_insn "*setcc_4"
    [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm"))
! 	(match_operator:QI 1 "uno_comparison_operator"
  	  [(reg:CC 17) (const_int 0)]))]
    ""
    "set%C1\\t%0"
***************
*** 6649,6655 ****
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (EQ, 1, operands[0]); DONE;")
  
  (define_expand "bne"
    [(set (pc)
--- 6697,6703 ----
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (EQ, operands[0]); DONE;")
  
  (define_expand "bne"
    [(set (pc)
***************
*** 6657,6663 ****
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (NE, 1, operands[0]); DONE;")
  
  (define_expand "bgt"
    [(set (pc)
--- 6705,6711 ----
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (NE, operands[0]); DONE;")
  
  (define_expand "bgt"
    [(set (pc)
***************
*** 6665,6671 ****
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (GT, 0, operands[0]); DONE;")
  
  (define_expand "bgtu"
    [(set (pc)
--- 6713,6719 ----
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (GT, operands[0]); DONE;")
  
  (define_expand "bgtu"
    [(set (pc)
***************
*** 6673,6679 ****
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (GTU, 0, operands[0]); DONE;")
  
  (define_expand "blt"
    [(set (pc)
--- 6721,6727 ----
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (GTU, operands[0]); DONE;")
  
  (define_expand "blt"
    [(set (pc)
***************
*** 6681,6687 ****
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (LT, 0, operands[0]); DONE;")
  
  (define_expand "bltu"
    [(set (pc)
--- 6729,6735 ----
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (LT, operands[0]); DONE;")
  
  (define_expand "bltu"
    [(set (pc)
***************
*** 6689,6695 ****
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (LTU, 0, operands[0]); DONE;")
  
  (define_expand "bge"
    [(set (pc)
--- 6737,6743 ----
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (LTU, operands[0]); DONE;")
  
  (define_expand "bge"
    [(set (pc)
***************
*** 6697,6703 ****
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (GE, 0, operands[0]); DONE;")
  
  (define_expand "bgeu"
    [(set (pc)
--- 6745,6751 ----
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (GE, operands[0]); DONE;")
  
  (define_expand "bgeu"
    [(set (pc)
***************
*** 6705,6711 ****
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (GEU, 0, operands[0]); DONE;")
  
  (define_expand "ble"
    [(set (pc)
--- 6753,6759 ----
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (GEU, operands[0]); DONE;")
  
  (define_expand "ble"
    [(set (pc)
***************
*** 6713,6719 ****
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (LE, 0, operands[0]); DONE;")
  
  (define_expand "bleu"
    [(set (pc)
--- 6761,6767 ----
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (LE, operands[0]); DONE;")
  
  (define_expand "bleu"
    [(set (pc)
***************
*** 6721,6728 ****
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (LEU, 0, operands[0]); DONE;")
  
  (define_insn "*jcc_1"
    [(set (pc)
  	(if_then_else (match_operator 0 "no_comparison_operator"
--- 6769,6840 ----
  		      (label_ref (match_operand 0 "" ""))
  		      (pc)))]
    ""
!   "ix86_expand_branch (LEU, operands[0]); DONE;")
! 
! (define_expand "bunordered"
!   [(set (pc)
! 	(if_then_else (match_dup 1)
! 		      (label_ref (match_operand 0 "" ""))
! 		      (pc)))]
!   "TARGET_80387"
!   "ix86_expand_branch (UNORDERED, operands[0]); DONE;")
! 
! (define_expand "bordered"
!   [(set (pc)
! 	(if_then_else (match_dup 1)
! 		      (label_ref (match_operand 0 "" ""))
! 		      (pc)))]
!   "TARGET_80387"
!   "ix86_expand_branch (ORDERED, operands[0]); DONE;")
! 
! (define_expand "buneq"
!   [(set (pc)
! 	(if_then_else (match_dup 1)
! 		      (label_ref (match_operand 0 "" ""))
! 		      (pc)))]
!   "TARGET_80387"
!   "ix86_expand_branch (UNEQ, operands[0]); DONE;")
  
+ (define_expand "bunge"
+   [(set (pc)
+ 	(if_then_else (match_dup 1)
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   "TARGET_80387"
+   "ix86_expand_branch (UNGE, operands[0]); DONE;")
+ 
+ (define_expand "bungt"
+   [(set (pc)
+ 	(if_then_else (match_dup 1)
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   "TARGET_80387"
+   "ix86_expand_branch (UNGT, operands[0]); DONE;")
+ 
+ (define_expand "bunle"
+   [(set (pc)
+ 	(if_then_else (match_dup 1)
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   "TARGET_80387"
+   "ix86_expand_branch (UNLE, operands[0]); DONE;")
+ 
+ (define_expand "bunlt"
+   [(set (pc)
+ 	(if_then_else (match_dup 1)
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   "TARGET_80387"
+   "ix86_expand_branch (UNLT, operands[0]); DONE;")
+ 
+ (define_expand "bltgt"
+   [(set (pc)
+ 	(if_then_else (match_dup 1)
+ 		      (label_ref (match_operand 0 "" ""))
+ 		      (pc)))]
+   "TARGET_80387"
+   "ix86_expand_branch (LTGT, operands[0]); DONE;")
+ 
  (define_insn "*jcc_1"
    [(set (pc)
  	(if_then_else (match_operator 0 "no_comparison_operator"
***************
*** 6759,6765 ****
  
  (define_insn "*jcc_3"
    [(set (pc)
! 	(if_then_else (match_operator 0 "comparison_operator"
  				      [(reg:CC 17) (const_int 0)])
  		      (label_ref (match_operand 1 "" ""))
  		      (pc)))]
--- 6871,6877 ----
  
  (define_insn "*jcc_3"
    [(set (pc)
! 	(if_then_else (match_operator 0 "uno_comparison_operator"
  				      [(reg:CC 17) (const_int 0)])
  		      (label_ref (match_operand 1 "" ""))
  		      (pc)))]
***************
*** 6776,6782 ****
  
  (define_insn "*jcc_4"
    [(set (pc)
! 	(if_then_else (match_operator 0 "comparison_operator"
  				      [(reg:CC 17) (const_int 0)])
  		      (pc)
  		      (label_ref (match_operand 1 "" ""))))]
--- 6888,6894 ----
  
  (define_insn "*jcc_4"
    [(set (pc)
! 	(if_then_else (match_operator 0 "uno_comparison_operator"
  				      [(reg:CC 17) (const_int 0)])
  		      (pc)
  		      (label_ref (match_operand 1 "" ""))))]
***************
*** 6790,6795 ****
--- 6902,7040 ----
  			       (const_int 124)))
  	  (const_int 2)
  	  (const_int 6)))])
+ 
+ ;; Define combination compare-and-branch fp compare instructions to use
+ ;; during early optimization.  Splitting the operation apart early makes
+ ;; for bad code when we want to reverse the operation.
+ 
+ (define_insn "*fp_jcc_1"
+   [(set (pc)
+ 	(if_then_else (match_operator 0 "comparison_operator"
+ 			[(match_operand 1 "register_operand" "f")
+ 			 (match_operand 2 "register_operand" "f")])
+ 	  (label_ref (match_operand 3 "" ""))
+ 	  (pc)))
+    (clobber (reg:CCFP 18))
+    (clobber (reg:CCFP 17))]
+   "TARGET_CMOVE && TARGET_80387
+    && FLOAT_MODE_P (GET_MODE (operands[1]))
+    && GET_MODE (operands[1]) == GET_MODE (operands[2])"
+   "#")
+ 
+ (define_insn "*fp_jcc_2"
+   [(set (pc)
+ 	(if_then_else (match_operator 0 "comparison_operator"
+ 			[(match_operand 1 "register_operand" "f")
+ 			 (match_operand 2 "register_operand" "f")])
+ 	  (pc)
+ 	  (label_ref (match_operand 3 "" ""))))
+    (clobber (reg:CCFP 18))
+    (clobber (reg:CCFP 17))]
+   "TARGET_CMOVE && TARGET_80387
+    && FLOAT_MODE_P (GET_MODE (operands[1]))
+    && GET_MODE (operands[1]) == GET_MODE (operands[2])"
+   "#")
+ 
+ (define_insn "*fp_jcc_3"
+   [(set (pc)
+ 	(if_then_else (match_operator:CCFP 0 "comparison_operator"
+ 			[(match_operand 1 "register_operand" "f")
+ 			 (match_operand 2 "nonimmediate_operand" "fm")])
+ 	  (label_ref (match_operand 3 "" ""))
+ 	  (pc)))
+    (clobber (reg:CCFP 18))
+    (clobber (reg:CCFP 17))
+    (clobber (match_scratch:HI 4 "=a"))]
+   "TARGET_80387
+    && (GET_MODE (operands[1]) == SFmode || GET_MODE (operands[1]) == DFmode)
+    && GET_MODE (operands[1]) == GET_MODE (operands[2])"
+   "#")
+ 
+ (define_insn "*fp_jcc_4"
+   [(set (pc)
+ 	(if_then_else (match_operator:CCFP 0 "comparison_operator"
+ 			[(match_operand 1 "register_operand" "f")
+ 			 (match_operand 2 "nonimmediate_operand" "fm")])
+ 	  (pc)
+ 	  (label_ref (match_operand 3 "" ""))))
+    (clobber (reg:CCFP 18))
+    (clobber (reg:CCFP 17))
+    (clobber (match_scratch:HI 4 "=a"))]
+   "TARGET_80387
+    && (GET_MODE (operands[1]) == SFmode || GET_MODE (operands[1]) == DFmode)
+    && GET_MODE (operands[1]) == GET_MODE (operands[2])"
+   "#")
+ 
+ (define_insn "*fp_jcc_5"
+   [(set (pc)
+ 	(if_then_else (match_operator 0 "comparison_operator"
+ 			[(match_operand 1 "register_operand" "f")
+ 			 (match_operand 2 "register_operand" "f")])
+ 	  (label_ref (match_operand 3 "" ""))
+ 	  (pc)))
+    (clobber (reg:CCFP 18))
+    (clobber (reg:CCFP 17))
+    (clobber (match_scratch:HI 4 "=a"))]
+   "TARGET_80387
+    && FLOAT_MODE_P (GET_MODE (operands[1]))
+    && GET_MODE (operands[1]) == GET_MODE (operands[2])"
+   "#")
+ 
+ (define_insn "*fp_jcc_6"
+   [(set (pc)
+ 	(if_then_else (match_operator 0 "comparison_operator"
+ 			[(match_operand 1 "register_operand" "f")
+ 			 (match_operand 2 "register_operand" "f")])
+ 	  (pc)
+ 	  (label_ref (match_operand 3 "" ""))))
+    (clobber (reg:CCFP 18))
+    (clobber (reg:CCFP 17))
+    (clobber (match_scratch:HI 4 "=a"))]
+   "TARGET_80387
+    && FLOAT_MODE_P (GET_MODE (operands[1]))
+    && GET_MODE (operands[1]) == GET_MODE (operands[2])"
+   "#")
+ 
+ (define_split
+   [(set (pc)
+ 	(if_then_else (match_operator 0 "comparison_operator"
+ 			[(match_operand 1 "register_operand" "")
+ 			 (match_operand 2 "nonimmediate_operand" "")])
+ 	  (match_operand 3 "" "")
+ 	  (match_operand 4 "" "")))
+    (clobber (reg:CCFP 18))
+    (clobber (reg:CCFP 17))]
+   "reload_completed"
+   [(set (pc)
+ 	(if_then_else (match_dup 5)
+ 	  (match_dup 3)
+ 	  (match_dup 4)))]
+   "
+ {
+   operands[5] = ix86_expand_fp_compare (GET_CODE (operands[0]), operands[1],
+ 					operands[2], NULL_RTX);
+ }")
+ 
+ (define_split
+   [(set (pc)
+ 	(if_then_else (match_operator 0 "comparison_operator"
+ 			[(match_operand 1 "register_operand" "")
+ 			 (match_operand 2 "nonimmediate_operand" "")])
+ 	  (match_operand 3 "" "")
+ 	  (match_operand 4 "" "")))
+    (clobber (reg:CCFP 18))
+    (clobber (reg:CCFP 17))
+    (clobber (match_scratch:HI 5 "=a"))]
+   "reload_completed"
+   [(set (pc)
+ 	(if_then_else (match_dup 6)
+ 	  (match_dup 3)
+ 	  (match_dup 4)))]
+   "
+ {
+   operands[6] = ix86_expand_fp_compare (GET_CODE (operands[0]), operands[1],
+ 					operands[2], operands[5]);
+ }")
  
  ;; Unconditional and other jump instructions
  
***************
*** 8768,8774 ****
  
  (define_insn "*movsicc_c"
    [(set (match_operand:SI 0 "register_operand" "=r,r")
! 	(if_then_else:SI (match_operator 1 "comparison_operator" 
  				[(reg:CC 17) (const_int 0)])
  		      (match_operand:SI 2 "nonimmediate_operand" "rm,0")
  		      (match_operand:SI 3 "nonimmediate_operand" "0,rm")))]
--- 9013,9019 ----
  
  (define_insn "*movsicc_c"
    [(set (match_operand:SI 0 "register_operand" "=r,r")
! 	(if_then_else:SI (match_operator 1 "uno_comparison_operator" 
  				[(reg:CC 17) (const_int 0)])
  		      (match_operand:SI 2 "nonimmediate_operand" "rm,0")
  		      (match_operand:SI 3 "nonimmediate_operand" "0,rm")))]
***************
*** 8802,8808 ****
  
  (define_insn "*movhicc_c"
    [(set (match_operand:HI 0 "register_operand" "=r,r")
! 	(if_then_else:HI (match_operator 1 "comparison_operator" 
  				[(reg:CC 17) (const_int 0)])
  		      (match_operand:HI 2 "nonimmediate_operand" "rm,0")
  		      (match_operand:HI 3 "nonimmediate_operand" "0,rm")))]
--- 9047,9053 ----
  
  (define_insn "*movhicc_c"
    [(set (match_operand:HI 0 "register_operand" "=r,r")
! 	(if_then_else:HI (match_operator 1 "uno_comparison_operator" 
  				[(reg:CC 17) (const_int 0)])
  		      (match_operand:HI 2 "nonimmediate_operand" "rm,0")
  		      (match_operand:HI 3 "nonimmediate_operand" "0,rm")))]


More information about the Gcc-patches mailing list