This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
i386 unordered comparisons using fcomi
- To: patches at x86-64 dot org, gcc-patches at gcc dot gnu dot org, rth at cygnus dot com
- Subject: i386 unordered comparisons using fcomi
- From: Jan Hubicka <jh at suse dot cz>
- Date: Thu, 4 Jan 2001 22:14:32 +0100
Hi
This patch adds support for using fcomi in the unordered comparisons.
This is the cheapest way to do the comparison in most cases, complication
comes with EQ, NE, LT, LE, UNGE, UNGT comparisons, that are not encodable
using single i386 condition, so you need to emit two jumps one checking
for the unordered case.
This unfortunate fact may be avoided by most cases by reversing or swapping
the condition, keeping only the EQ/NE tests problematic, but these are
not too important for fp anyway.
I handle all the weirdness in function ix86_fp_comparison_codes, that
is able to split the nonexisting conditions to the existing and
ix86_fp_compare_code_to_integer that converts the real conparison codes
to the codes for integer instructions.
I need this patch to implement SSE scalar arithmetics support, since the
fcom equivalent is not present on the chip.
With this patch I can no longer measure difference between normal compilation
and -ffast-math. I've measured consistent speedups on both Athlon and celeron
in same order as -ffast-math was delivering us till now.
Honza
Thu Jan 4 22:00:23 MET 2001 Jan Hubicka <jh@suse.cz>
* i386.c (ix86_single_test_fcomi, ix86_fp_compare_code_to_integer,
ix86_fp_comparison_codes): New functions.
(ix86_comparison_operator): Accept the proper codes for FP comparisons.
(fcmov_comparison_operator): Likewise.
(put_condition_code): Convert FP comparisons to integer ones.
(ix86_use_fcomi_compare): Return true in all cases when fcomi available.
(ix86_expand_fp_compare): Attempt to optimize the condition; add
add_test and bypass_test parameter; use fcomi when possible.
(ix86_expand_compare): Update call of ix86_expand_fp_compare.
(ix86_expand_fp_movcc): Simplify test of availability the condition code;
use ix86_expand_compare instead of emitting comparison by hand.
* i386.h (REVERSIBLE_CC_MODE): New macro.
(PREDICATE_CODES): Add unordered cases to the ix86_comparison_operator.
* i386.md (conditional jump splitter): Use ix86_split_fcomi_branch.
* i386-protos.h (ix86_expand_fp_compare): Update prototype.
(ix86_split_fcomi_branch): Declare.
*** i386/i386.c Tue Jan 2 19:27:11 2001
--- a/i386/i386.c Wed Aug 9 23:50:19 2000
*************** static rtx ix86_expand_unop_builtin PARA
*** 434,439 ****
--- 434,445 ----
static rtx ix86_expand_binop_builtin PARAMS ((enum insn_code, tree, rtx));
static rtx ix86_expand_store_builtin PARAMS ((enum insn_code, tree, int));
static rtx safe_vector_operand PARAMS ((rtx, enum machine_mode));
+ static int ix86_single_test_fcomi PARAMS ((enum rtx_code));
+ static enum rtx_code ix86_fp_compare_code_to_integer PARAMS ((enum rtx_code));
+ static void ix86_fp_comparison_codes PARAMS ((enum rtx_code code,
+ enum rtx_code *,
+ enum rtx_code *,
+ enum rtx_code *));
/* Sometimes certain combinations of command options do not make
sense on a particular target machine. You can define a macro
*************** ix86_comparison_operator (op, mode)
*** 1297,1310 ****
enum machine_mode mode;
{
enum machine_mode inmode;
if (mode != VOIDmode && GET_MODE (op) != mode)
return 0;
! switch (GET_CODE (op))
{
case EQ: case NE:
return 1;
case LT: case GE:
- inmode = GET_MODE (XEXP (op, 0));
if (inmode == CCmode || inmode == CCGCmode
|| inmode == CCGOCmode || inmode == CCNOmode)
return 1;
--- 1301,1333 ----
enum machine_mode mode;
{
enum machine_mode inmode;
+ enum rtx_code code;
if (mode != VOIDmode && GET_MODE (op) != mode)
return 0;
! code = GET_CODE (op);
! if (GET_RTX_CLASS (code) != '<')
! return 0;
! inmode = GET_MODE (XEXP (op, 0));
! if (inmode == CCFPmode && !TARGET_IEEE_FP)
! switch (code)
! {
! case EQ: case NE: case LTGT: case UNEQ:
! case LT: case GE: case GT: case LE:
! case UNLT: case UNGE: case UNGT: case UNLE:
! case ORDERED: case UNORDERED:
! return 1;
! default:
! return 0;
! }
! else if (inmode == CCFPmode)
! return ix86_fp_compare_mode (code) == CCFPmode;
! if (inmode == CCFPUmode)
! return ix86_fp_compare_code_to_integer (code) != NIL;
! switch (code)
{
case EQ: case NE:
return 1;
case LT: case GE:
if (inmode == CCmode || inmode == CCGCmode
|| inmode == CCGOCmode || inmode == CCNOmode)
return 1;
*************** fcmov_comparison_operator (op, mode)
*** 1331,1345 ****
register rtx op;
enum machine_mode mode;
{
! enum machine_mode inmode = GET_MODE (XEXP (op, 0));
if (mode != VOIDmode && GET_MODE (op) != mode)
return 0;
switch (GET_CODE (op))
{
case EQ: case NE:
return 1;
case LTU: case GTU: case LEU: case ORDERED: case UNORDERED: case GEU:
! if (inmode == CCFPmode || inmode == CCFPUmode)
return 1;
return 0;
default:
--- 1354,1382 ----
register rtx op;
enum machine_mode mode;
{
! enum machine_mode inmode;
! enum rtx_code code = GET_CODE (op);
if (mode != VOIDmode && GET_MODE (op) != mode)
return 0;
+ if (GET_RTX_CLASS (code) != '<')
+ return 0;
+ inmode = GET_MODE (XEXP (op, 0));
+ if (inmode == CCFPmode)
+ {
+ enum rtx_code bypass_code, second_code;
+ if (!ix86_comparison_operator (op, mode))
+ return 0;
+ ix86_fp_comparison_codes (code, &bypass_code, &code, &second_code);
+ code = ix86_fp_compare_code_to_integer (code);
+ }
+ if (inmode == CCFPUmode)
+ code = ix86_fp_compare_code_to_integer (code);
switch (GET_CODE (op))
{
case EQ: case NE:
return 1;
case LTU: case GTU: case LEU: case ORDERED: case UNORDERED: case GEU:
! if (inmode == CCmode || inmode == CCFPmode || inmode == CCFPUmode)
return 1;
return 0;
default:
*************** put_condition_code (code, mode, reverse,
*** 3091,3106 ****
{
const char *suffix;
+ if (mode == CCFPmode)
+ {
+ enum rtx_code bypass_code, second_code;
+ ix86_fp_comparison_codes (code, &bypass_code, &code, &second_code);
+ if (bypass_code != NIL || second_code !=NIL)
+ abort ();
+ if (code == NIL)
+ abort ();
+ }
+ if (mode == CCFPmode || mode == CCFPUmode)
+ {
+ code = ix86_fp_compare_code_to_integer (code);
+ mode = CCmode;
+ }
+
if (reverse)
code = reverse_condition (code);
switch (code)
{
*************** ix86_cc_mode (code, op0, op1)
*** 4738,4755 ****
abort ();
}
}
/* Return true if we should use an FCOMI instruction for this fp comparison. */
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
--- 4815,4841 ----
abort ();
}
}
+ /* Return true if we should use an FCOMI instruction for this fp comparison
+ followed by only one test. */
+
+ static int
+ ix86_single_test_fcomi (code)
+ enum rtx_code code;
+ {
+ enum rtx_code bypass_code, first_code, second_code;
+ if (!TARGET_CMOVE)
+ return 0;
+ ix86_fp_comparison_codes (code, &bypass_code, &first_code, &second_code);
+ return bypass_code == NIL && second_code == NIL;
+ }
/* Return true if we should use an FCOMI instruction for this fp comparison. */
int
ix86_use_fcomi_compare (code)
! enum rtx_code code ATTRIBUTE_UNUSED;
{
! return TARGET_CMOVE;
}
/* Swap, force into registers, or otherwise massage the two operands
*************** ix86_prepare_fp_compare_args (code, pop0
*** 4805,4839 ****
}
}
*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
{
--- 4890,5056 ----
}
}
+ /* Attempt to avoid second jump by swapping the comparison operands. */
+ if (!ix86_single_test_fcomi (code)
+ && ix86_single_test_fcomi (swap_condition (code)))
+ {
+ rtx tmp;
+ tmp = op0, op0 = op1, op1 = tmp;
+ code = swap_condition (code);
+ if (GET_CODE (op0) != REG)
+ op0 = force_reg (op_mode, op0);
+ }
+
*pop0 = op0;
*pop1 = op1;
return code;
}
+ /* Convert comparison codes we use to represent FP comparison to integer
+ code that will result in proper branch. Return NIL if no such code
+ is available. */
+ static enum rtx_code
+ ix86_fp_compare_code_to_integer (code)
+ enum rtx_code code;
+ {
+ switch (code)
+ {
+ case GT:
+ return GTU;
+ case GE:
+ return GEU;
+ case ORDERED:
+ case UNORDERED:
+ return code;
+ break;
+ case UNEQ:
+ return EQ;
+ break;
+ case UNLT:
+ return LTU;
+ break;
+ case UNLE:
+ return LEU;
+ break;
+ case LTGT:
+ return NE;
+ break;
+ default:
+ return NIL;
+ }
+ }
+
+ /* Split comparison code CODE into comparisons we can do using branch
+ instructions. BYPASS_CODE is comparison code for branch that will
+ branch around FIRST_CODE and SECOND_CODE. If some of branches
+ is not required, set value to NIL.
+ We never require more than two branches. */
+ static void
+ ix86_fp_comparison_codes (code, bypass_code, first_code, second_code)
+ enum rtx_code code, *bypass_code, *first_code, *second_code;
+ {
+ *first_code = code;
+ *bypass_code = NIL;
+ *second_code = NIL;
+
+ /* The fcomi comparison sets flags as follows:
+
+ cmp ZF PF CF
+ > 0 0 0
+ < 0 0 1
+ = 1 0 0
+ un 1 1 1 */
+
+ switch (code)
+ {
+ case GT: /* GTU - CF=0 & ZF=0 */
+ case GE: /* GEU - CF=0 */
+ case ORDERED: /* PF=0 */
+ case UNORDERED: /* PF=1 */
+ case UNEQ: /* EQ - ZF=1 */
+ case UNLT: /* LTU - CF=1 */
+ case UNLE: /* LEU - CF=1 | ZF=1 */
+ case LTGT: /* EQ - ZF=0 */
+ break;
+ case LT: /* LTU - CF=1 - fails on unordered */
+ *first_code = UNLT;
+ *bypass_code = UNORDERED;
+ break;
+ case LE: /* LEU - CF=1 | ZF=1 - fails on unordered */
+ *first_code = UNLE;
+ *bypass_code = UNORDERED;
+ break;
+ case EQ: /* EQ - ZF=1 - fails on unordered */
+ *first_code = UNEQ;
+ *bypass_code = UNORDERED;
+ break;
+ case NE: /* NE - ZF=0 - fails on unordered */
+ *first_code = LTGT;
+ *second_code = UNORDERED;
+ break;
+ case UNGE: /* GEU - CF=0 - fails on unordered */
+ *first_code = GE;
+ *second_code = UNORDERED;
+ break;
+ case UNGT: /* GTU - CF=0 & ZF=0 - fails on unordered */
+ *first_code = GT;
+ *second_code = UNORDERED;
+ break;
+ default:
+ abort ();
+ }
+ if (!TARGET_IEEE_FP)
+ {
+ *second_code = NIL;
+ *bypass_code = NIL;
+ }
+ }
+
/* Generate insn patterns to do a floating point compare of OPERANDS. */
rtx
! ix86_expand_fp_compare (code, op0, op1, scratch, add_test, bypass_test)
enum rtx_code code;
rtx op0, op1, scratch;
+ rtx *add_test;
+ rtx *bypass_test;
{
enum machine_mode fpcmp_mode, intcmp_mode;
rtx tmp;
fpcmp_mode = ix86_fp_compare_mode (code);
+ if (add_test)
+ *add_test = NULL_RTX;
+ if (bypass_test)
+ *bypass_test = NULL_RTX;
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_single_test_fcomi (code) || add_test)
{
+ enum rtx_code add_code = NIL;
+ enum rtx_code bypass_code = NIL;
tmp = gen_rtx_COMPARE (fpcmp_mode, op0, op1);
tmp = gen_rtx_SET (VOIDmode, gen_rtx_REG (fpcmp_mode, FLAGS_REG), tmp);
emit_insn (tmp);
! ix86_fp_comparison_codes (code, &bypass_code, &code, &add_code);
! intcmp_mode = fpcmp_mode;
! if (add_code != NIL)
! {
! /* Manage add_code to be the less predicable one. */
! enum rtx_code tmp_code = add_code;
! add_code = code;
! code = tmp_code;
!
! *add_test = gen_rtx_fmt_ee (add_code, VOIDmode,
! gen_rtx_REG (intcmp_mode, FLAGS_REG),
! const0_rtx);
! }
! if (bypass_code != NIL)
! *bypass_test = gen_rtx_fmt_ee (bypass_code, VOIDmode,
! gen_rtx_REG (intcmp_mode, FLAGS_REG),
! const0_rtx);
}
else
{
*************** ix86_expand_compare (code)
*** 5022,5028 ****
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);
--- 5249,5256 ----
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),
! NULL, NULL);
else
ret = ix86_expand_int_compare (code, op0, op1);
*************** ix86_expand_branch (code, label)
*** 5199,5204 ****
--- 5426,5507 ----
}
}
+ /* Split branch that will use the FCOMI instruction. */
+ void
+ ix86_split_fcomi_branch (condition, op1, op2, target1, target2)
+ rtx condition, op1, op2, target1, target2;
+ {
+ rtx add, bypass;
+ rtx label = NULL_RTX;
+ enum rtx_code code = GET_CODE (condition);
+ enum rtx_code bypass_code, second_code, first;
+ if (!ix86_single_test_fcomi (code))
+ {
+ /* Attempt to re-arrange the comparison in order to do only single test. */
+ if (ix86_single_test_fcomi (swap_condition (code))
+ && GET_CODE (op1) == REG)
+ {
+ rtx tmp = op1;
+ op1 = op2;
+ op2 = tmp;
+ code = swap_condition (code);
+ }
+ /* In case we can swap the operands, arrange condition in a way bypass
+ is not required. This helps the branch prediction and reduces number
+ of basic blocks. */
+ else if (GET_CODE (op1) == REG)
+ {
+ ix86_fp_comparison_codes (code, &bypass_code, &first, &second_code);
+ if ((target2 == pc_rtx && bypass_code != NIL)
+ || (target2 != pc_rtx && second_code != NIL))
+ {
+ rtx tmp = target1;
+ target1 = target2;
+ target2 = tmp;
+ code = reverse_condition (code);
+ }
+ }
+ }
+ condition = ix86_expand_fp_compare (code, op1, op2,
+ NULL_RTX, &add, &bypass);
+ if (target2 != pc_rtx)
+ {
+ rtx tmp = bypass;
+ bypass = add;
+ add = tmp;
+ }
+ if (bypass != NULL_RTX)
+ {
+ label = gen_label_rtx ();
+ emit_jump_insn (gen_rtx_SET
+ (VOIDmode, pc_rtx,
+ gen_rtx_IF_THEN_ELSE (VOIDmode,
+ bypass,
+ gen_rtx_LABEL_REF (VOIDmode,
+ label),
+ pc_rtx)));
+ }
+ /* AMD Athlon and probably other CPUs too have fast bypass path between the
+ comparison and first branch. The second branch takes longer to execute
+ so place first branch the worse predicable one if possible. */
+ if (add != NULL_RTX && GET_CODE (add) == UNORDERED)
+ {
+ rtx tmp = condition;
+ condition = add;
+ add = tmp;
+ }
+ emit_jump_insn (gen_rtx_SET
+ (VOIDmode, pc_rtx,
+ gen_rtx_IF_THEN_ELSE (VOIDmode,
+ condition, target1, target2)));
+ if (add != NULL_RTX)
+ emit_jump_insn (gen_rtx_SET
+ (VOIDmode, pc_rtx,
+ gen_rtx_IF_THEN_ELSE (VOIDmode, add, target1, target2)));
+ if (label != NULL_RTX)
+ emit_label (label);
+ }
+
int
ix86_expand_setcc (code, dest)
enum rtx_code code;
*************** ix86_expand_fp_movcc (operands)
*** 5588,5631 ****
enum rtx_code code;
enum machine_mode mode;
rtx tmp;
/* The floating point conditional move instructions don't directly
! support conditions resulting from a signed integer comparison. */
! code = GET_CODE (operands[1]);
! switch (code)
{
- case LT:
- case LE:
- case GE:
- case GT:
- case UNEQ:
- case UNGE:
- case UNGT:
- case UNLE:
- case UNLT:
- case LTGT:
tmp = gen_reg_rtx (QImode);
ix86_expand_setcc (code, tmp);
code = NE;
ix86_compare_op0 = tmp;
ix86_compare_op1 = const0_rtx;
! break;
!
! default:
! break;
}
- mode = SELECT_CC_MODE (code, ix86_compare_op0, ix86_compare_op1);
- emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, FLAGS_REG),
- gen_rtx_COMPARE (mode,
- ix86_compare_op0,
- ix86_compare_op1)));
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
! gen_rtx_fmt_ee (code, VOIDmode,
! gen_rtx_REG (mode, FLAGS_REG),
! const0_rtx),
operands[2],
operands[3])));
--- 5891,5916 ----
enum rtx_code code;
enum machine_mode mode;
rtx tmp;
+ rtx compare_op;
+ code = GET_CODE (operands[1]);
+ compare_op = ix86_expand_compare (code);
/* The floating point conditional move instructions don't directly
! support signed integer comparisons. */
! if (!fcmov_comparison_operator (compare_op, VOIDmode))
{
tmp = gen_reg_rtx (QImode);
ix86_expand_setcc (code, tmp);
code = NE;
ix86_compare_op0 = tmp;
ix86_compare_op1 = const0_rtx;
! compare_op = ix86_expand_compare (code);
}
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
! compare_op,
operands[2],
operands[3])));
*** i386/i386.h Wed Jan 3 19:21:52 2001
--- a/i386/i386.h Wed Aug 9 20:47:42 2000
*************** while (0)
*** 2118,2123 ****
--- 2096,2107 ----
between pointers and any other objects of this machine mode. */
#define Pmode SImode
+ /* Return non-zero if MODE implies a floating point inequality can be
+ reversed. For i386 this is always true because we have a full
+ compliment of ordered and unordered comparisons, but until generic
+ code knows how to reverse it correctly we keep the old definition. */
+ #define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPUmode)
+
/* A function address in a call instruction
is a byte address (for indexing purposes)
*************** do { long l; \
*** 2845,2851 ****
{"fcmov_comparison_operator", {EQ, NE, LTU, GTU, LEU, GEU}}, \
{"sse_comparison_operator", {EQ, LT, LE, UNORDERED }}, \
{"ix86_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}}, \
--- 2829,2836 ----
{"fcmov_comparison_operator", {EQ, NE, LTU, GTU, LEU, GEU}}, \
{"sse_comparison_operator", {EQ, LT, LE, UNORDERED }}, \
{"ix86_comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, \
! GTU, UNORDERED, ORDERED, UNEQ, UNGE, \
! UNGT, UNLE, UNLT, LTGT}}, \
{"cmp_fp_expander_operand", {CONST_DOUBLE, SUBREG, REG, MEM}}, \
{"ext_register_operand", {SUBREG, REG}}, \
{"binary_fp_operator", {PLUS, MINUS, MULT, DIV}}, \
*** i386/i386.md Tue Jan 2 19:27:11 2001
--- a/i386/i386.md Wed Aug 9 20:13:43 2000
***************
*** 9304,9317 ****
(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
--- 8888,8899 ----
(clobber (reg:CCFP 18))
(clobber (reg:CCFP 17))]
"reload_completed"
! [(const_int 0)]
"
{
! ix86_split_fcomi_branch (operands[0], operands[1], operands[2],
! operands[3], operands[4]);
! DONE;
}")
(define_split
***************
*** 9332,9338 ****
"
{
operands[6] = ix86_expand_fp_compare (GET_CODE (operands[0]), operands[1],
! operands[2], operands[5]);
}")
;; Unconditional and other jump instructions
--- 8914,8921 ----
"
{
operands[6] = ix86_expand_fp_compare (GET_CODE (operands[0]), operands[1],
! operands[2], operands[5],
! NULL_RTX, NULL_RTX);
}")
;; Unconditional and other jump instructions
*** i386/i386-protos.h Mon Nov 27 17:23:26 2000
--- a/i386/i386-protos.h Wed Aug 9 21:02:38 2000
*************** extern void ix86_expand_unary_operator P
*** 102,108 ****
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 rtx ix86_expand_compare PARAMS ((enum rtx_code));
extern int ix86_use_fcomi_compare PARAMS ((enum rtx_code));
extern void ix86_expand_branch PARAMS ((enum rtx_code, rtx));
--- 102,108 ----
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, rtx *, rtx *));
extern rtx ix86_expand_compare PARAMS ((enum rtx_code));
extern int ix86_use_fcomi_compare PARAMS ((enum rtx_code));
extern void ix86_expand_branch PARAMS ((enum rtx_code, rtx));
*************** extern enum machine_mode ix86_fp_compare
*** 130,135 ****
--- 130,136 ----
extern rtx ix86_force_to_memory PARAMS ((enum machine_mode, rtx));
extern void ix86_free_from_memory PARAMS ((enum machine_mode));
+ extern void ix86_split_fcomi_branch PARAMS ((rtx, rtx, rtx, rtx, rtx));
#ifdef TREE_CODE
extern void init_cumulative_args PARAMS ((CUMULATIVE_ARGS *, tree, rtx));