summaryrefslogtreecommitdiff
path: root/gcc/reg-stack.c
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>1999-09-02 04:20:21 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>1999-09-02 04:20:21 +0000
commitce71a9e62981c51534492d55d5bf99a08c89853a (patch)
tree2741b1e654e069ae0926889ad907a3122fc70944 /gcc/reg-stack.c
parent830a572acbd17d6fb8ae39e7fec9decda08af939 (diff)
downloadgcc-ce71a9e62981c51534492d55d5bf99a08c89853a.tar.gz
Merge new ia32 backend from the branch!
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@29044 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/reg-stack.c')
-rw-r--r--gcc/reg-stack.c802
1 files changed, 419 insertions, 383 deletions
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
index 4da5a7a85dd..d9c40483358 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -160,8 +160,8 @@ Boston, MA 02111-1307, USA. */
#include "hard-reg-set.h"
#include "flags.h"
#include "insn-flags.h"
-#include "recog.h"
#include "toplev.h"
+#include "recog.h"
#include "varray.h"
#ifdef STACK_REGS
@@ -232,26 +232,13 @@ static rtx
/* Get the basic block number of an insn. See note at block_number
definition are validity of this information. */
-static int BLOCK_NUM PROTO((rtx));
-
-#ifdef __GNUC__
-__inline__
-#endif
-static int
-BLOCK_NUM(insn)
- rtx insn;
-{
- int tmp = INSN_UID (insn);
- if (tmp > max_uid)
- abort ();
- tmp = block_number[tmp];
- if (tmp < 0)
- abort ();
- return tmp;
-}
+#define BLOCK_NUM(INSN) \
+ ((INSN_UID (INSN) > max_uid) \
+ ? (abort() , -1) : block_number[INSN_UID (INSN)])
/* Forward declarations */
+static int stack_regs_mentioned_p PROTO((rtx pat));
static void mark_regs_pat PROTO((rtx, HARD_REG_SET *));
static void straighten_stack PROTO((rtx, stack));
static void pop_stack PROTO((stack, int));
@@ -273,7 +260,8 @@ static void delete_insn_for_stacker PROTO((rtx));
static rtx emit_pop_insn PROTO((rtx, stack, rtx, rtx (*) ()));
static void emit_swap_insn PROTO((rtx, stack, rtx));
static void move_for_stack_reg PROTO((rtx, stack, rtx));
-static void swap_rtx_condition PROTO((rtx));
+static int swap_rtx_condition_1 PROTO((rtx));
+static int swap_rtx_condition PROTO((rtx));
static void compare_for_stack_reg PROTO((rtx, stack, rtx));
static void subst_stack_regs_pat PROTO((rtx, stack, rtx));
static void subst_asm_stack_regs PROTO((rtx, stack));
@@ -284,47 +272,96 @@ static void goto_block_pat PROTO((rtx, stack, rtx));
static void convert_regs PROTO((void));
static void print_blocks PROTO((FILE *, rtx, rtx));
static void dump_stack_info PROTO((FILE *));
-static int check_stack_regs_mentioned PROTO((rtx insn));
-/* Initialize stack_regs_mentioned_data for INSN (growing the virtual array
- if needed. Return nonzero if INSN mentions stacked registers. */
+/* Return non-zero if any stack register is mentioned somewhere within PAT. */
static int
-check_stack_regs_mentioned (insn)
- rtx insn;
+stack_regs_mentioned_p (pat)
+ rtx pat;
{
- unsigned int uid = INSN_UID (insn);
- if (uid >= VARRAY_SIZE (stack_regs_mentioned_data))
- /* Allocate some extra size to avoid too many reallocs, but
- do not grow exponentially. */
- VARRAY_GROW (stack_regs_mentioned_data, uid + uid / 20);
- if (stack_regs_mentioned_p (PATTERN (insn)))
+ register const char *fmt;
+ register int i;
+
+ if (STACK_REG_P (pat))
+ return 1;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (pat));
+ for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
{
- VARRAY_CHAR (stack_regs_mentioned_data, uid) = 1;
- return 1;
+ if (fmt[i] == 'E')
+ {
+ register int j;
+
+ for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
+ if (stack_regs_mentioned_p (XVECEXP (pat, i, j)))
+ return 1;
+ }
+ else if (fmt[i] == 'e' && stack_regs_mentioned_p (XEXP (pat, i)))
+ return 1;
}
- else
- VARRAY_CHAR (stack_regs_mentioned_data, uid) = 2;
+
return 0;
}
-/* Return nonzero if INSN mentions stacked registers, else return
- zero. */
+/* Return nonzero if INSN mentions stacked registers, else return zero. */
int
stack_regs_mentioned (insn)
rtx insn;
{
- unsigned int uid;
+ unsigned int uid, max;
+ int test;
+
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
return 0;
+
uid = INSN_UID (insn);
- if (uid >= VARRAY_SIZE (stack_regs_mentioned_data)
- || ! VARRAY_CHAR (stack_regs_mentioned_data, uid))
- return (check_stack_regs_mentioned (insn));
- return VARRAY_CHAR (stack_regs_mentioned_data, uid) == 1;
+ max = VARRAY_SIZE (stack_regs_mentioned_data);
+ if (uid >= max)
+ {
+ /* Allocate some extra size to avoid too many reallocs, but
+ do not grow too quickly. */
+ max = uid + uid / 20;
+ VARRAY_GROW (stack_regs_mentioned_data, max);
+ }
+
+ test = VARRAY_CHAR (stack_regs_mentioned_data, uid);
+ if (test == 0)
+ {
+ /* This insn has yet to be examined. Do so now. */
+ test = stack_regs_mentioned_p (PATTERN (insn)) ? 1 : 2;
+ VARRAY_CHAR (stack_regs_mentioned_data, uid) = test;
+ }
+
+ return test == 1;
}
+
+static rtx ix86_flags_rtx;
+static rtx
+next_flags_user (insn)
+ rtx insn;
+{
+ /* Search forward looking for the first use of this value.
+ Stop at block boundaries. */
+ /* ??? This really cries for BLOCK_END! */
+
+ while (1)
+ {
+ insn = NEXT_INSN (insn);
+ if (!insn)
+ return NULL_RTX;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && reg_mentioned_p (ix86_flags_rtx, PATTERN (insn)))
+ return insn;
+
+ if (GET_CODE (insn) == JUMP_INSN
+ || GET_CODE (insn) == CODE_LABEL
+ || GET_CODE (insn) == CALL_INSN)
+ return NULL_RTX;
+ }
+}
/* Mark all registers needed for this pattern. */
@@ -338,17 +375,17 @@ mark_regs_pat (pat, set)
register int count;
if (GET_CODE (pat) == SUBREG)
- {
- mode = GET_MODE (pat);
- regno = SUBREG_WORD (pat);
- regno += REGNO (SUBREG_REG (pat));
- }
+ {
+ mode = GET_MODE (pat);
+ regno = SUBREG_WORD (pat);
+ regno += REGNO (SUBREG_REG (pat));
+ }
else
- regno = REGNO (pat), mode = GET_MODE (pat);
+ regno = REGNO (pat), mode = GET_MODE (pat);
for (count = HARD_REGNO_NREGS (regno, mode);
count; count--, regno++)
- SET_HARD_REG_BIT (*set, regno);
+ SET_HARD_REG_BIT (*set, regno);
}
/* Reorganise the stack into ascending numbers,
@@ -372,7 +409,7 @@ straighten_stack (insn, regstack)
temp_stack.reg_set = regstack->reg_set;
for (top = temp_stack.top = regstack->top; top >= 0; top--)
- temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top;
+ temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top;
change_stack (insn, regstack, &temp_stack, emit_insn_after);
}
@@ -403,36 +440,6 @@ pop_stack (regstack, regno)
}
}
-/* Return non-zero if any stack register is mentioned somewhere within PAT. */
-
-int
-stack_regs_mentioned_p (pat)
- rtx pat;
-{
- register const char *fmt;
- register int i;
-
- if (STACK_REG_P (pat))
- return 1;
-
- fmt = GET_RTX_FORMAT (GET_CODE (pat));
- for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'E')
- {
- register int j;
-
- for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
- if (stack_regs_mentioned_p (XVECEXP (pat, i, j)))
- return 1;
- }
- else if (fmt[i] == 'e' && stack_regs_mentioned_p (XEXP (pat, i)))
- return 1;
- }
-
- return 0;
-}
-
/* Convert register usage from "flat" register file usage to a "stack
register file. FIRST is the first insn in the function, FILE is the
dump file, if used.
@@ -454,15 +461,17 @@ reg_to_stack (first, file)
enum machine_mode mode;
HARD_REG_SET stackentry;
+ ix86_flags_rtx = gen_rtx_REG (CCmode, FLAGS_REG);
+
max_uid = get_max_uid ();
VARRAY_CHAR_INIT (stack_regs_mentioned_data, max_uid + 1,
"stack_regs_mentioned cache");
CLEAR_HARD_REG_SET (stackentry);
- {
- static int initialised;
- if (!initialised)
+ {
+ static int initialised;
+ if (!initialised)
{
#if 0
initialised = 1; /* This array can not have been previously
@@ -471,16 +480,16 @@ reg_to_stack (first, file)
functions. */
#endif
for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
- {
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
+ {
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT); mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT); mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
- }
+ }
}
- }
+ }
/* Count the basic blocks. Also find maximum insn uid. */
{
@@ -509,7 +518,7 @@ reg_to_stack (first, file)
blocks++;
if (code == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
- before_function_beg = 0;
+ before_function_beg = 0;
/* Remember whether or not this insn mentions an FP regs.
Check JUMP_INSNs too, in case someone creates a funny PARALLEL. */
@@ -518,7 +527,7 @@ reg_to_stack (first, file)
&& stack_regs_mentioned_p (PATTERN (insn)))
{
stack_reg_seen = 1;
- VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 1;
+ VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 1;
/* Note any register passing parameters. */
@@ -565,7 +574,6 @@ reg_to_stack (first, file)
bzero ((char *) block_out_reg_set, blocks * sizeof (HARD_REG_SET));
block_number = (int *) alloca ((max_uid + 1) * sizeof (int));
- memset (block_number, -1, (max_uid + 1) * sizeof (int));
find_blocks (first);
stack_reg_life_analysis (first, &stackentry);
@@ -648,32 +656,30 @@ get_true_reg (pat)
rtx *pat;
{
for (;;)
- switch (GET_CODE (*pat))
+ switch (GET_CODE (*pat))
{
- case SUBREG:
- /* eliminate FP subregister accesses in favour of the
- actual FP register in use. */
- {
- rtx subreg;
- if (FP_REG_P (subreg = SUBREG_REG (*pat)))
+ case SUBREG:
+ /* Eliminate FP subregister accesses in favour of the
+ actual FP register in use. */
+ {
+ rtx subreg;
+ if (FP_REG_P (subreg = SUBREG_REG (*pat)))
{
*pat = FP_MODE_REG (REGNO (subreg) + SUBREG_WORD (*pat),
GET_MODE (subreg));
- default:
+ default:
return pat;
}
- }
- case FLOAT:
- case FIX:
- case FLOAT_EXTEND:
- pat = & XEXP (*pat, 0);
+ }
+ case FLOAT:
+ case FIX:
+ case FLOAT_EXTEND:
+ pat = & XEXP (*pat, 0);
}
}
/* Record the life info of each stack reg in INSN, updating REGSTACK.
N_INPUTS is the number of inputs; N_OUTPUTS the outputs.
- OPERANDS is an array of all operands for the insn, and is assumed to
- contain all output operands, then all inputs operands.
There are many rules that an asm statement for stack-like regs must
follow. Those rules are explained at the top of this file: the rule
@@ -712,7 +718,7 @@ record_asm_reg_life (insn, regstack)
malformed_asm = 1;
/* Avoid further trouble with this insn. */
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
- VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 2;
+ PUT_MODE (insn, VOIDmode);
return;
}
@@ -917,10 +923,10 @@ record_reg_life_pat (pat, src, dest, douse)
|| (GET_CODE (pat) == SUBREG && STACK_REG_P (SUBREG_REG (pat))))
{
if (src)
- mark_regs_pat (pat, src);
+ mark_regs_pat (pat, src);
if (dest)
- mark_regs_pat (pat, dest);
+ mark_regs_pat (pat, dest);
return;
}
@@ -1022,74 +1028,74 @@ record_reg_life (insn, block, regstack)
return;
}
- {
- HARD_REG_SET src, dest;
- int regno;
-
- CLEAR_HARD_REG_SET (src);
- CLEAR_HARD_REG_SET (dest);
-
- if (GET_CODE (insn) == CALL_INSN)
- for (note = CALL_INSN_FUNCTION_USAGE (insn);
- note;
- note = XEXP (note, 1))
- if (GET_CODE (XEXP (note, 0)) == USE)
- record_reg_life_pat (SET_DEST (XEXP (note, 0)), &src, NULL_PTR, 0);
-
- record_reg_life_pat (PATTERN (insn), &src, &dest, 0);
- for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)
- if (! TEST_HARD_REG_BIT (regstack->reg_set, regno))
- {
- if (TEST_HARD_REG_BIT (src, regno)
- && ! TEST_HARD_REG_BIT (dest, regno))
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
- FP_MODE_REG (regno, DFmode),
- REG_NOTES (insn));
- else if (TEST_HARD_REG_BIT (dest, regno))
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED,
- FP_MODE_REG (regno, DFmode),
- REG_NOTES (insn));
- }
+ {
+ HARD_REG_SET src, dest;
+ int regno;
+
+ CLEAR_HARD_REG_SET (src);
+ CLEAR_HARD_REG_SET (dest);
+
+ if (GET_CODE (insn) == CALL_INSN)
+ for (note = CALL_INSN_FUNCTION_USAGE (insn);
+ note;
+ note = XEXP (note, 1))
+ if (GET_CODE (XEXP (note, 0)) == USE)
+ record_reg_life_pat (SET_DEST (XEXP (note, 0)), &src, NULL_PTR, 0);
+
+ record_reg_life_pat (PATTERN (insn), &src, &dest, 0);
+ for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)
+ if (! TEST_HARD_REG_BIT (regstack->reg_set, regno))
+ {
+ if (TEST_HARD_REG_BIT (src, regno)
+ && ! TEST_HARD_REG_BIT (dest, regno))
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
+ FP_MODE_REG (regno, DFmode),
+ REG_NOTES (insn));
+ else if (TEST_HARD_REG_BIT (dest, regno))
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED,
+ FP_MODE_REG (regno, DFmode),
+ REG_NOTES (insn));
+ }
- if (GET_CODE (insn) == CALL_INSN)
- {
- int reg;
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ int reg;
- /* There might be a reg that is live after a function call.
- Initialize it to zero so that the program does not crash. See
- comment towards the end of stack_reg_life_analysis(). */
+ /* There might be a reg that is live after a function call.
+ Initialize it to zero so that the program does not crash. See
+ comment towards the end of stack_reg_life_analysis(). */
- for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++)
- if (! TEST_HARD_REG_BIT (dest, reg)
- && TEST_HARD_REG_BIT (regstack->reg_set, reg))
- {
- rtx init, pat;
+ for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++)
+ if (! TEST_HARD_REG_BIT (dest, reg)
+ && TEST_HARD_REG_BIT (regstack->reg_set, reg))
+ {
+ rtx init, pat;
- /* The insn will use virtual register numbers, and so
- convert_regs is expected to process these. But BLOCK_NUM
- cannot be used on these insns, because they do not appear in
- block_number[]. */
+ /* The insn will use virtual register numbers, and so
+ convert_regs is expected to process these. But BLOCK_NUM
+ cannot be used on these insns, because they do not appear in
+ block_number[]. */
- pat = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, DFmode),
- CONST0_RTX (DFmode));
- init = emit_insn_after (pat, insn);
+ pat = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, DFmode),
+ CONST0_RTX (DFmode));
+ init = emit_insn_after (pat, insn);
- CLEAR_HARD_REG_BIT (regstack->reg_set, reg);
+ CLEAR_HARD_REG_BIT (regstack->reg_set, reg);
- /* If the CALL_INSN was the end of a block, move the
- block_end to point to the new insn. */
+ /* If the CALL_INSN was the end of a block, move the
+ block_end to point to the new insn. */
- if (block_end[block] == insn)
- block_end[block] = init;
- }
+ if (block_end[block] == insn)
+ block_end[block] = init;
+ }
- /* Some regs do not survive a CALL */
- AND_COMPL_HARD_REG_SET (regstack->reg_set, call_used_reg_set);
- }
+ /* Some regs do not survive a CALL */
+ AND_COMPL_HARD_REG_SET (regstack->reg_set, call_used_reg_set);
+ }
- AND_COMPL_HARD_REG_SET (regstack->reg_set, dest);
- IOR_HARD_REG_SET (regstack->reg_set, src);
- }
+ AND_COMPL_HARD_REG_SET (regstack->reg_set, dest);
+ IOR_HARD_REG_SET (regstack->reg_set, src);
+ }
}
/* Find all basic blocks of the function, which starts with FIRST.
@@ -1240,26 +1246,26 @@ stack_reg_life_analysis (first, stackentry)
int reg, block;
struct stack_def regstack;
- {
- rtx retvalue;
+ {
+ rtx retvalue;
- if ((retvalue = stack_result (current_function_decl)))
+ if ((retvalue = stack_result (current_function_decl)))
{
/* Find all RETURN insns and mark them. */
for (block = blocks - 1; --block >= 0;)
- if (GET_CODE (block_end[block]) == JUMP_INSN
- && returnjump_p (block_end[block]))
- mark_regs_pat (retvalue, block_out_reg_set+block);
+ if (GET_CODE (block_end[block]) == JUMP_INSN
+ && returnjump_p (block_end[block]))
+ mark_regs_pat (retvalue, block_out_reg_set+block);
/* Mark off the end of last block if we "fall off" the end of the
function into the epilogue. */
if (GET_CODE (block_end[blocks-1]) != JUMP_INSN
- || returnjump_p (block_end[blocks-1]))
+ || GET_CODE (PATTERN (block_end[blocks-1])) == RETURN)
mark_regs_pat (retvalue, block_out_reg_set+blocks-1);
}
- }
+ }
/* now scan all blocks backward for stack register use */
@@ -1343,10 +1349,10 @@ stack_reg_life_analysis (first, stackentry)
block -= 1;
}
- /* If any reg is live at the start of the first block of a
- function, then we must guarantee that the reg holds some value by
- generating our own "load" of that register. Otherwise a 387 would
- fault trying to access an empty register. */
+ /* If any reg is live at the start of the first block of a
+ function, then we must guarantee that the reg holds some value by
+ generating our own "load" of that register. Otherwise a 387 would
+ fault trying to access an empty register. */
/* Load zero into each live register. The fact that a register
appears live at the function start necessarily implies an error
@@ -1373,10 +1379,10 @@ stack_reg_life_analysis (first, stackentry)
}
}
-/*****************************************************************************
- This section deals with stack register substitution, and forms the second
- pass over the RTL.
- *****************************************************************************/
+/*
+ * This section deals with stack register substitution, and forms the second
+ * pass over the RTL.
+ */
/* Replace REG, which is a pointer to a stack reg RTX, with an RTX for
the desired hard REGNO. */
@@ -1391,11 +1397,11 @@ replace_reg (reg, regno)
abort ();
switch (GET_MODE_CLASS (GET_MODE (*reg)))
- {
- default: abort ();
- case MODE_FLOAT:
- case MODE_COMPLEX_FLOAT:;
- }
+ {
+ default: abort ();
+ case MODE_FLOAT:
+ case MODE_COMPLEX_FLOAT:;
+ }
*reg = FP_MODE_REG (regno, GET_MODE (*reg));
}
@@ -1454,14 +1460,6 @@ static void
delete_insn_for_stacker (insn)
rtx insn;
{
- int i;
-
- /* Ensure that the side effects were clobbers when deleting a PARALLEL. */
- if (GET_CODE (PATTERN (insn)) == PARALLEL)
- for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
- if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) != CLOBBER)
- abort ();
-
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
@@ -1469,12 +1467,9 @@ delete_insn_for_stacker (insn)
/* Emit an insn to pop virtual register REG before or after INSN.
REGSTACK is the stack state after INSN and is updated to reflect this
- pop. WHEN is either emit_insn_before, emit_insn_after or NULL.
- in case WHEN is NULL we don't really emit the insn, just modify stack
- information. Caller is expected to emit insn himself.
-
- A pop insn is represented as a SET whose destination is the register to
- be popped and source is the top of stack. A death note for the top of stack
+ pop. WHEN is either emit_insn_before or emit_insn_after. A pop insn
+ is represented as a SET whose destination is the register to be popped
+ and source is the top of stack. A death note for the top of stack
cases the movdf pattern to pop. */
static rtx
@@ -1492,18 +1487,14 @@ emit_pop_insn (insn, regstack, reg, when)
if (hard_regno < FIRST_STACK_REG)
abort ();
- if (when)
- {
- pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode),
- FP_MODE_REG (FIRST_STACK_REG, DFmode));
+ pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode),
+ FP_MODE_REG (FIRST_STACK_REG, DFmode));
- pop_insn = (*when) (pop_rtx, insn);
+ pop_insn = (*when) (pop_rtx, insn);
- REG_NOTES (pop_insn) = gen_rtx_EXPR_LIST (REG_DEAD,
- FP_MODE_REG (FIRST_STACK_REG,
- DFmode),
- REG_NOTES (pop_insn));
- }
+ REG_NOTES (pop_insn) = gen_rtx_EXPR_LIST (REG_DEAD,
+ FP_MODE_REG (FIRST_STACK_REG, DFmode),
+ REG_NOTES (pop_insn));
regstack->reg[regstack->top - (hard_regno - FIRST_STACK_REG)]
= regstack->reg[regstack->top];
@@ -1528,7 +1519,6 @@ emit_swap_insn (insn, regstack, reg)
rtx reg;
{
int hard_regno;
- rtx gen_swapdf();
rtx swap_rtx, swap_insn;
int tmp, other_reg; /* swap regno temps */
rtx i1; /* the stack-reg insn prior to INSN */
@@ -1578,15 +1568,8 @@ emit_swap_insn (insn, regstack, reg)
return;
}
- if (GET_RTX_CLASS (GET_CODE (i1)) == 'i' && sets_cc0_p (PATTERN (i1)))
- {
- i1 = next_nonnote_insn (i1);
- if (i1 == insn)
- abort ();
- }
-
- swap_rtx = gen_swapdf (FP_MODE_REG (hard_regno, DFmode),
- FP_MODE_REG (FIRST_STACK_REG, DFmode));
+ swap_rtx = gen_swapxf (FP_MODE_REG (hard_regno, XFmode),
+ FP_MODE_REG (FIRST_STACK_REG, XFmode));
swap_insn = emit_insn_after (swap_rtx, i1);
}
@@ -1732,109 +1715,144 @@ move_for_stack_reg (insn, regstack, pat)
abort ();
}
-static void
-swap_rtx_condition (pat)
+/* Swap the condition on a branch, if there is one. Return true if we
+ found a condition to swap. False if the condition was not used as
+ such. */
+
+static int
+swap_rtx_condition_1 (pat)
rtx pat;
{
register const char *fmt;
- register int i;
+ register int i, r = 0;
if (GET_RTX_CLASS (GET_CODE (pat)) == '<')
{
PUT_CODE (pat, swap_condition (GET_CODE (pat)));
- return;
+ r = 1;
}
-
- fmt = GET_RTX_FORMAT (GET_CODE (pat));
- for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
+ else
{
- if (fmt[i] == 'E')
+ fmt = GET_RTX_FORMAT (GET_CODE (pat));
+ for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
{
- register int j;
+ if (fmt[i] == 'E')
+ {
+ register int j;
- for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
- swap_rtx_condition (XVECEXP (pat, i, j));
+ for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
+ r |= swap_rtx_condition_1 (XVECEXP (pat, i, j));
+ }
+ else if (fmt[i] == 'e')
+ r |= swap_rtx_condition_1 (XEXP (pat, i));
}
- else if (fmt[i] == 'e')
- swap_rtx_condition (XEXP (pat, i));
}
+
+ return r;
+}
+
+static int
+swap_rtx_condition (insn)
+ rtx insn;
+{
+ rtx pat = PATTERN (insn);
+
+ /* We're looking for a single set to cc0 or an HImode temporary. */
+
+ if (GET_CODE (pat) == SET
+ && GET_CODE (SET_DEST (pat)) == REG
+ && REGNO (SET_DEST (pat)) == FLAGS_REG)
+ {
+ insn = next_flags_user (insn);
+ if (insn == NULL_RTX)
+ return 0;
+ pat = PATTERN (insn);
+ }
+
+ /* See if this is, or ends in, a fnstsw, aka unspec 9. If so, we're
+ not doing anything with the cc value right now. We may be able to
+ search for one though. */
+
+ if (GET_CODE (pat) == SET
+ && GET_CODE (SET_SRC (pat)) == UNSPEC
+ && XINT (SET_SRC (pat), 1) == 9)
+ {
+ rtx dest = SET_DEST (pat);
+
+ /* Search forward looking for the first use of this value.
+ Stop at block boundaries. */
+ /* ??? This really cries for BLOCK_END! */
+ while (1)
+ {
+ insn = NEXT_INSN (insn);
+ if (insn == NULL_RTX)
+ return 0;
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && reg_mentioned_p (dest, insn))
+ break;
+ if (GET_CODE (insn) == JUMP_INSN)
+ return 0;
+ if (GET_CODE (insn) == CODE_LABEL)
+ return 0;
+ }
+
+ /* So we've found the insn using this value. If it is anything
+ other than sahf, aka unspec 10, or the value does not die
+ (meaning we'd have to search further), then we must give up. */
+ pat = PATTERN (insn);
+ if (GET_CODE (pat) != SET
+ || GET_CODE (SET_SRC (pat)) != UNSPEC
+ || XINT (SET_SRC (pat), 1) != 10
+ || ! dead_or_set_p (insn, dest))
+ return 0;
+
+ /* Now we are prepared to handle this as a normal cc0 setter. */
+ insn = next_flags_user (insn);
+ if (insn == NULL_RTX)
+ return 0;
+ pat = PATTERN (insn);
+ }
+
+ return swap_rtx_condition_1 (pat);
}
/* Handle a comparison. Special care needs to be taken to avoid
causing comparisons that a 387 cannot do correctly, such as EQ.
- Also, a fstp instruction may need to be emitted. The 387 does have an
+ Also, a pop insn may need to be emitted. The 387 does have an
`fcompp' insn that can pop two regs, but it is sometimes too expensive
to do this - a `fcomp' followed by a `fstpl %st(0)' may be easier to
- set up.
-
- We can not handle this by emiting fpop instruction after compare, because
- it appears between cc0 setter and user. So we emit only
- REG_DEAD note and handle it as a special case in machine description.
-
- This code used trick with delay_slot filling to emit pop insn after
- comparsion but it didn't worked because it caused confusion with cc_status
- in final pass. */
+ set up. */
static void
-compare_for_stack_reg (insn, regstack, pat)
+compare_for_stack_reg (insn, regstack, pat_src)
rtx insn;
stack regstack;
- rtx pat;
+ rtx pat_src;
{
rtx *src1, *src2;
rtx src1_note, src2_note;
- rtx cc0_user;
- int have_cmove;
- int hard_regno;
+ rtx flags_user;
- src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
- src2 = get_true_reg (&XEXP (SET_SRC (pat), 1));
- cc0_user = next_cc0_user (insn);
-
- /* If the insn that uses cc0 is an FP-conditional move, then the destination
- must be the top of stack */
- if (GET_CODE (PATTERN (cc0_user)) == SET
- && SET_DEST (PATTERN (cc0_user)) != pc_rtx
- && GET_CODE (SET_SRC (PATTERN (cc0_user))) == IF_THEN_ELSE
- && (GET_MODE_CLASS (GET_MODE (SET_DEST (PATTERN (cc0_user))))
- == MODE_FLOAT))
- {
- rtx *dest;
-
- dest = get_true_reg (&SET_DEST (PATTERN (cc0_user)));
-
- have_cmove = 1;
- if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG
- && REGNO (*dest) != regstack->reg[regstack->top])
- {
- emit_swap_insn (insn, regstack, *dest);
- }
- }
- else
- have_cmove = 0;
+ src1 = get_true_reg (&XEXP (pat_src, 0));
+ src2 = get_true_reg (&XEXP (pat_src, 1));
+ flags_user = next_flags_user (insn);
/* ??? If fxch turns out to be cheaper than fstp, give priority to
registers that die in this insn - move those to stack top first. */
- if (! STACK_REG_P (*src1)
- || (STACK_REG_P (*src2)
- && get_hard_regnum (regstack, *src2) == FIRST_STACK_REG))
+ if ((! STACK_REG_P (*src1)
+ || (STACK_REG_P (*src2)
+ && get_hard_regnum (regstack, *src2) == FIRST_STACK_REG))
+ && swap_rtx_condition (insn))
{
- rtx temp, next;
-
- temp = XEXP (SET_SRC (pat), 0);
- XEXP (SET_SRC (pat), 0) = XEXP (SET_SRC (pat), 1);
- XEXP (SET_SRC (pat), 1) = temp;
+ rtx temp;
+ temp = XEXP (pat_src, 0);
+ XEXP (pat_src, 0) = XEXP (pat_src, 1);
+ XEXP (pat_src, 1) = temp;
- src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
- src2 = get_true_reg (&XEXP (SET_SRC (pat), 1));
-
- next = next_cc0_user (insn);
- if (next == NULL_RTX)
- abort ();
+ src1 = get_true_reg (&XEXP (pat_src, 0));
+ src2 = get_true_reg (&XEXP (pat_src, 1));
- swap_rtx_condition (PATTERN (next));
- INSN_CODE (next) = -1;
INSN_CODE (insn) = -1;
}
@@ -1847,16 +1865,12 @@ compare_for_stack_reg (insn, regstack, pat)
else
src2_note = NULL_RTX;
- if (! have_cmove)
- emit_swap_insn (insn, regstack, *src1);
+ emit_swap_insn (insn, regstack, *src1);
replace_reg (src1, FIRST_STACK_REG);
if (STACK_REG_P (*src2))
- {
- hard_regno = get_hard_regnum (regstack, *src2);
- replace_reg (src2, hard_regno);
- }
+ replace_reg (src2, get_hard_regnum (regstack, *src2));
if (src1_note)
{
@@ -1885,11 +1899,16 @@ compare_for_stack_reg (insn, regstack, pat)
}
else
{
- /* Pop of second operand is handled using special REG_DEAD note
- because we can't emit pop insn after cc0 setter. */
+ /* The 386 can only represent death of the first operand in
+ the case handled above. In all other cases, emit a separate
+ pop and remove the death note from here. */
+
+ /* link_cc0_insns (insn); */
- emit_pop_insn (insn, regstack, XEXP (src2_note, 0), NULL);
- replace_reg (&XEXP (src2_note, 0), hard_regno);
+ remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0)));
+
+ emit_pop_insn (insn, regstack, XEXP (src2_note, 0),
+ emit_insn_after);
}
}
}
@@ -1906,12 +1925,14 @@ subst_stack_regs_pat (insn, regstack, pat)
rtx *dest, *src;
rtx *src1 = (rtx *) NULL_PTR, *src2;
rtx src1_note, src2_note;
+ rtx pat_src;
if (GET_CODE (pat) != SET)
return;
dest = get_true_reg (&SET_DEST (pat));
src = get_true_reg (&SET_SRC (pat));
+ pat_src = SET_SRC (pat);
/* See if this is a `movM' pattern, and handle elsewhere if so. */
@@ -1922,22 +1943,22 @@ subst_stack_regs_pat (insn, regstack, pat)
|| GET_CODE (*src) == CONST_DOUBLE))))
move_for_stack_reg (insn, regstack, pat);
else
- switch (GET_CODE (SET_SRC (pat)))
+ switch (GET_CODE (pat_src))
{
case COMPARE:
- compare_for_stack_reg (insn, regstack, pat);
+ compare_for_stack_reg (insn, regstack, pat_src);
break;
case CALL:
- {
- int count;
- for (count = HARD_REGNO_NREGS (REGNO (*dest), GET_MODE (*dest));
- --count >= 0;)
+ {
+ int count;
+ for (count = HARD_REGNO_NREGS (REGNO (*dest), GET_MODE (*dest));
+ --count >= 0;)
{
regstack->reg[++regstack->top] = REGNO (*dest) + count;
SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest) + count);
}
- }
+ }
replace_reg (dest, FIRST_STACK_REG);
break;
@@ -1960,7 +1981,7 @@ subst_stack_regs_pat (insn, regstack, pat)
source. */
if (src1 == 0)
- src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
+ src1 = get_true_reg (&XEXP (pat_src, 0));
emit_swap_insn (insn, regstack, *src1);
@@ -1992,8 +2013,8 @@ subst_stack_regs_pat (insn, regstack, pat)
source and some other stack register (possibly top of stack)
as a destination. */
- src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
- src2 = get_true_reg (&XEXP (SET_SRC (pat), 1));
+ src1 = get_true_reg (&XEXP (pat_src, 0));
+ src2 = get_true_reg (&XEXP (pat_src, 1));
/* We will fix any death note later. */
@@ -2095,13 +2116,13 @@ subst_stack_regs_pat (insn, regstack, pat)
break;
case UNSPEC:
- switch (XINT (SET_SRC (pat), 1))
+ switch (XINT (pat_src, 1))
{
case 1: /* sin */
case 2: /* cos */
/* These insns only operate on the top of the stack. */
- src1 = get_true_reg (&XVECEXP (SET_SRC (pat), 0, 0));
+ src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
emit_swap_insn (insn, regstack, *src1);
@@ -2121,16 +2142,35 @@ subst_stack_regs_pat (insn, regstack, pat)
break;
+ case 10:
+ /* (unspec [(unspec [(compare ..)] 9)] 10)
+ Unspec 9 is fnstsw; unspec 10 is sahf. The combination
+ matches the PPRO fcomi instruction. */
+
+ pat_src = XVECEXP (pat_src, 0, 0);
+ if (GET_CODE (pat_src) != UNSPEC
+ || XINT (pat_src, 1) != 9)
+ abort ();
+ /* FALLTHRU */
+
+ case 9:
+ /* (unspec [(compare ..)] 9)
+ Combined fcomp+fnstsw generated for doing well with CSE.
+ When optimizing this would have been broken up before now. */
+
+ pat_src = XVECEXP (pat_src, 0, 0);
+ if (GET_CODE (pat_src) != COMPARE)
+ abort ();
+
+ compare_for_stack_reg (insn, regstack, pat_src);
+ break;
+
default:
abort ();
}
break;
case IF_THEN_ELSE:
- /* dest has to be on stack. */
- if (get_hard_regnum (regstack, *dest) < FIRST_STACK_REG)
- abort ();
-
/* This insn requires the top of stack to be the destination. */
/* If the comparison operator is an FP comparison operator,
@@ -2142,8 +2182,8 @@ subst_stack_regs_pat (insn, regstack, pat)
&& REGNO (*dest) != regstack->reg[regstack->top])
emit_swap_insn (insn, regstack, *dest);
- src1 = get_true_reg (&XEXP (SET_SRC (pat), 1));
- src2 = get_true_reg (&XEXP (SET_SRC (pat), 2));
+ src1 = get_true_reg (&XEXP (pat_src, 1));
+ src2 = get_true_reg (&XEXP (pat_src, 2));
src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
@@ -2184,7 +2224,9 @@ subst_stack_regs_pat (insn, regstack, pat)
}
}
- /* Make dest the top of stack. */
+ /* Make dest the top of stack. Add dest to regstack if not present. */
+ if (get_hard_regnum (regstack, *dest) < FIRST_STACK_REG)
+ regstack->reg[++regstack->top] = REGNO (*dest);
SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
replace_reg (dest, FIRST_STACK_REG);
@@ -2500,26 +2542,26 @@ subst_stack_regs (insn, regstack)
register int i;
if (GET_CODE (insn) == CALL_INSN)
- {
- int top = regstack->top;
+ {
+ int top = regstack->top;
- /* If there are any floating point parameters to be passed in
- registers for this call, make sure they are in the right
- order. */
+ /* If there are any floating point parameters to be passed in
+ registers for this call, make sure they are in the right
+ order. */
- if (top >= 0)
- {
- straighten_stack (PREV_INSN (insn), regstack);
+ if (top >= 0)
+ {
+ straighten_stack (PREV_INSN (insn), regstack);
- /* Now mark the arguments as dead after the call. */
+ /* Now mark the arguments as dead after the call. */
- while (regstack->top >= 0)
- {
- CLEAR_HARD_REG_BIT (regstack->reg_set, FIRST_STACK_REG + regstack->top);
- regstack->top--;
- }
- }
- }
+ while (regstack->top >= 0)
+ {
+ CLEAR_HARD_REG_BIT (regstack->reg_set, FIRST_STACK_REG + regstack->top);
+ regstack->top--;
+ }
+ }
+ }
/* Do the actual substitution if any stack regs are mentioned.
Since we only record whether entire insn mentions stack regs, and
@@ -2544,14 +2586,8 @@ subst_stack_regs (insn, regstack)
for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
{
if (stack_regs_mentioned_p (XVECEXP (PATTERN (insn), 0, i)))
- {
- subst_stack_regs_pat (insn, regstack,
- XVECEXP (PATTERN (insn), 0, i));
-
- /* subst_stack_regs_pat may have deleted a no-op insn. */
- if (GET_CODE (insn) == NOTE)
- break;
- }
+ subst_stack_regs_pat (insn, regstack,
+ XVECEXP (PATTERN (insn), 0, i));
}
else
subst_stack_regs_pat (insn, regstack, PATTERN (insn));
@@ -2712,27 +2748,27 @@ goto_block_pat (insn, regstack, pat)
int reg;
switch (GET_CODE (pat))
- {
- case RETURN:
- straighten_stack (PREV_INSN (insn), regstack);
- return;
- default:
- {
- int i, j;
- const char *fmt = GET_RTX_FORMAT (GET_CODE (pat));
-
- for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- goto_block_pat (insn, regstack, XEXP (pat, i));
- if (fmt[i] == 'E')
- for (j = 0; j < XVECLEN (pat, i); j++)
- goto_block_pat (insn, regstack, XVECEXP (pat, i, j));
- }
+ {
+ case RETURN:
+ straighten_stack (PREV_INSN (insn), regstack);
return;
- }
- case LABEL_REF:;
- }
+ default:
+ {
+ int i, j;
+ const char *fmt = GET_RTX_FORMAT (GET_CODE (pat));
+
+ for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ goto_block_pat (insn, regstack, XEXP (pat, i));
+ if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (pat, i); j++)
+ goto_block_pat (insn, regstack, XVECEXP (pat, i, j));
+ }
+ return;
+ }
+ case LABEL_REF:;
+ }
label = XEXP (pat, 0);
if (GET_CODE (label) != CODE_LABEL)
@@ -2896,26 +2932,26 @@ convert_regs ()
regs live at its start, then the last basic block will have regs live
at its end that need to be popped before the function returns. */
- {
- int value_reg_low, value_reg_high;
- value_reg_low = value_reg_high = -1;
- {
- rtx retvalue;
- if ((retvalue = stack_result (current_function_decl)))
- {
- value_reg_low = REGNO (retvalue);
- value_reg_high = value_reg_low +
+ {
+ int value_reg_low, value_reg_high;
+ value_reg_low = value_reg_high = -1;
+ {
+ rtx retvalue;
+ if ((retvalue = stack_result (current_function_decl)))
+ {
+ value_reg_low = REGNO (retvalue);
+ value_reg_high = value_reg_low +
HARD_REGNO_NREGS (value_reg_low, GET_MODE (retvalue)) - 1;
- }
+ }
- }
- for (reg = regstack.top; reg >= 0; reg--)
- if (regstack.reg[reg] < value_reg_low
- || regstack.reg[reg] > value_reg_high)
- insn = emit_pop_insn (insn, &regstack,
- FP_MODE_REG (regstack.reg[reg], DFmode),
- emit_insn_after);
- }
+ }
+ for (reg = regstack.top; reg >= 0; reg--)
+ if (regstack.reg[reg] < value_reg_low
+ || regstack.reg[reg] > value_reg_high)
+ insn = emit_pop_insn (insn, &regstack,
+ FP_MODE_REG (regstack.reg[reg], DFmode),
+ emit_insn_after);
+ }
straighten_stack (insn, &regstack);
}