Commit c572e5ba by James Van Artsdalen

*** empty log message ***

From-SVN: r808
parent 5944b57e
......@@ -45,6 +45,7 @@ extern char *strcat ();
char *singlemove_string ();
char *output_move_const_single ();
char *output_fp_cc0_set ();
static char *hi_reg_name[] = HI_REGISTER_NAMES;
static char *qi_reg_name[] = QI_REGISTER_NAMES;
......@@ -65,6 +66,12 @@ enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
/* arg pointer */
INDEX_REGS
};
/* Test and compare insns in i386.md store the information needed to
generate branch and scc insns here. */
struct rtx_def *i386_compare_op0, *i386_compare_op1;
struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
/* Output an insn whose source is a 386 integer register. SRC is the
rtx for the register, and TEMPLATE is the op-code template. SRC may
......@@ -1353,6 +1360,8 @@ notice_update_cc (exp)
CC_STATUS_INIT;
if (! stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
cc_status.flags |= CC_IN_80387;
return;
}
CC_STATUS_INIT;
......@@ -1679,7 +1688,8 @@ output_fix_trunc (insn, operands)
/* Output code for INSN to compare OPERANDS. The two operands might
not have the same mode: one might be within a FLOAT or FLOAT_EXTEND
expression. */
expression. If the compare is in mode CCFPEQmode, use an opcode that
will not fault if a qNaN is present. */
char *
output_float_compare (insn, operands)
......@@ -1687,6 +1697,8 @@ output_float_compare (insn, operands)
rtx *operands;
{
int stack_top_dies;
rtx body = XVECEXP (PATTERN (insn), 0, 0);
int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode;
if (! STACK_TOP_P (operands[0]))
abort ();
......@@ -1702,15 +1714,21 @@ output_float_compare (insn, operands)
is also a stack register that dies, then this must be a
`fcompp' float compare */
output_asm_insn ("fcompp", operands);
if (unordered_compare)
output_asm_insn ("fucompp", operands);
else
output_asm_insn ("fcompp", operands);
}
else
{
static char buf[100];
/* Decide if this is the integer or float compare opcode. */
/* Decide if this is the integer or float compare opcode, or the
unordered float compare. */
if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
if (unordered_compare)
strcpy (buf, "fucom");
else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
strcpy (buf, "fcom");
else
strcpy (buf, "ficom");
......@@ -1728,10 +1746,102 @@ output_float_compare (insn, operands)
/* Now retrieve the condition code. */
output_asm_insn (AS1 (fnsts%W2,%2), operands);
return output_fp_cc0_set (insn);
}
/* Output opcodes to transfer the results of FP compare or test INSN
from the FPU to the CPU flags. If TARGET_IEEE_FP, ensure that if the
result of the compare or test is unordered, no comparison operator
succeeds except NE. Return an output template, if any. */
char *
output_fp_cc0_set (insn)
rtx insn;
{
rtx xops[3];
rtx unordered_label;
rtx next;
enum rtx_code code;
xops[0] = gen_rtx (REG, HImode, 0);
output_asm_insn (AS1 (fnsts%W0,%0), xops);
if (! TARGET_IEEE_FP)
return "sahf";
cc_status.flags |= CC_IN_80387;
return "sahf";
next = next_cc0_user (insn);
if (GET_CODE (next) == JUMP_INSN
&& GET_CODE (PATTERN (next)) == SET
&& SET_DEST (PATTERN (next)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
{
code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
}
else if (GET_CODE (PATTERN (next)) == SET)
{
code = GET_CODE (SET_SRC (PATTERN (next)));
}
else
abort ();
xops[0] = gen_rtx (REG, QImode, 0);
switch (code)
{
case GT:
xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
/* je label */
break;
case LT:
xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x01);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
/* je label */
break;
case GE:
xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x05);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
/* je label */
break;
case LE:
xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
output_asm_insn (AS1 (dec%B0,%h0), xops);
output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
/* jb label */
break;
case EQ:
xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x45);
xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
/* je label */
break;
case NE:
xops[1] = gen_rtx (CONST_INT, VOIDmode, 0x44);
xops[2] = gen_rtx (CONST_INT, VOIDmode, 0x40);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
output_asm_insn (AS2 (xor%B0,%2,%h0), xops);
/* jne label */
break;
case GTU:
case LTU:
case GEU:
case LEU:
default:
abort ();
}
RET;
}
#ifdef HANDLE_PRAGMA
......
......@@ -61,6 +61,11 @@ extern int target_flags;
Meaningful only on svr3. */
#define TARGET_SVR3_SHLIB (target_flags & 040)
/* Use IEEE floating point comparisons. These handle correctly the cases
where the result of a comparison is unordered. Normally SIGFPE is
generated in such cases, in which case this isn't needed. */
#define TARGET_IEEE_FP (target_flags & 0100)
/* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces,
each pair being { "NAME", VALUE }
......@@ -79,6 +84,8 @@ extern int target_flags;
{ "noregparm", -020}, \
{ "svr3-shlib", 040}, \
{ "nosvr3-shlib", -040}, \
{ "ieee-fp", 0100}, \
{ "noieee-fp", -0100}, \
{ "", TARGET_DEFAULT}}
/* target machine storage layout */
......@@ -1146,6 +1153,33 @@ while (0)
: REG_P (RTX) ? 1 \
: 2)
/* Add any extra modes needed to represent the condition code.
For the i386, we need separate modes when floating-point equality
comparisons are being done. */
#define EXTRA_CC_MODES CCFPEQmode
/* Define the names for the modes specified above. */
#define EXTRA_CC_NAMES "CCFPEQ"
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison.
For floating-point equality comparisons, CCFPEQmode should be used.
VOIDmode should be used in all other cases. */
#define SELECT_CC_MODE(OP,X) \
(GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
&& ((OP) == EQ || (OP) == NE) ? CCFPEQmode : CCmode)
/* Define the information needed to generate branch and scc insns. This is
stored from the compare operation. Note that we can't use "rtx" here
since it hasn't been defined! */
extern struct rtx_def *i386_compare_op0, *i386_compare_op1;
extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
/* Tell final.c how to eliminate redundant test instructions. */
/* Here we define machine-dependent flags and fields in cc_status
......
......@@ -1516,6 +1516,23 @@ prev_label (insn)
}
#ifdef HAVE_cc0
/* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER
and REG_CC_USER notes so we can find it. */
void
link_cc0_insns (insn)
rtx insn;
{
rtx user = next_nonnote_insn (insn);
if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE)
user = XVECEXP (PATTERN (user), 0, 0);
REG_NOTES (user) = gen_rtx (INSN_LIST, REG_CC_SETTER, insn,
REG_NOTES (user));
REG_NOTES (insn) = gen_rtx (INSN_LIST, REG_CC_USER, user, REG_NOTES (insn));
}
/* Return the next insn that uses CC0 after INSN, which is assumed to
set it. This is the inverse of prev_cc0_setter (i.e., prev_cc0_setter
applied to the result of this function should yield INSN).
......
......@@ -1825,6 +1825,8 @@ compare_for_stack_reg (insn, regstack, pat)
the case handled above. In all other cases, emit a separate
pop and remove the death note from here. */
link_cc0_insns (insn);
remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0)));
emit_pop_insn (insn, regstack, XEXP (src2_note, 0),
......
......@@ -779,25 +779,6 @@ add_to_delay_list (insn, delay_list)
return delay_list;
}
#ifdef HAVE_cc0
/* INSN uses CC0 and is being moved into a delay slot. Set up REG_CC_SETTER
and REG_CC_USER notes so we can find it. */
static void
link_cc0_insns (insn)
rtx insn;
{
rtx user = next_nonnote_insn (insn);
if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE)
user = XVECEXP (PATTERN (user), 0, 0);
REG_NOTES (user) = gen_rtx (INSN_LIST, REG_CC_SETTER, insn,
REG_NOTES (user));
REG_NOTES (insn) = gen_rtx (INSN_LIST, REG_CC_USER, user, REG_NOTES (insn));
}
#endif
/* Delete INSN from the the delay slot of the insn that it is in. This may
produce an insn without anything in its delay slots. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment