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