summaryrefslogtreecommitdiff
path: root/gcc/reg-stack.c
diff options
context:
space:
mode:
authorkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>1995-04-25 23:06:57 +0000
committerkenner <kenner@138bc75d-0d04-0410-961f-82ee72b054a4>1995-04-25 23:06:57 +0000
commita5dff55eb885cf86b0674d0cffbf9c9f87dae9b9 (patch)
tree07e2e31b8acac457b6f22931a37ac1e81d4703d9 /gcc/reg-stack.c
parent0cb99219c0a61929e465590ad4c0fd197ee5ca50 (diff)
downloadgcc-a5dff55eb885cf86b0674d0cffbf9c9f87dae9b9.tar.gz
(current_function_returns_real): Deleted (unused).
(FP_mode_reg): Trimmed to a smaller size, less overhead. (FP_MODE_REG): New macro over which FP_mode_reg will be accessed. (mark_regs_pat, straighten_stack): New functions. (reg_to_stack): Amend initialisation of FP_mode_reg. Mark FP registers mentioned in USE insns before NOTE_INSN_FUNCTION_BEG. (get_true_reg): Eliminate FP subreg accesses in favour of the actual FP register in use. (record_reg_life_pat): Make it work on SUBREGs as well. Make use of the new mark_regs_pat function. Handle USE insns if called unnested. (record_reg_life): Don't check for QImode again, we know that it is there. Process CALL_INSNs like all other insns, they might `use' some FP argument registers if register passing. (stack_result_p): Changed in stack_result and returning an rtx. (stack_reg_life_analysis): Take a new stackentry state argument. Use stack_result and the rtx to mark using mark_regs_pat. This ensures that types that need multiple FP registers are handled correctly Delete the no_live_regs shortcut to save space. Use stackentry state to determine filled registers. (replace_reg): Accept COMPLEX_FLOAT as well. (move_for_stack_reg): Optimise away some pointer dereferencing. (subst_stack_regs): Make sure the stack is in the right order and of the right size for register passing. (goto_block_pat): Make sure the stack is in the right order to return possible multi-register values from the function. (convert_regs): Fix comment about CALL_INSN, it's no longer valid. Make sure the stack is of the right size and in the right order to return possible multi-register values from the function. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@9459 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/reg-stack.c')
-rw-r--r--gcc/reg-stack.c477
1 files changed, 302 insertions, 175 deletions
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
index df45dd4980a..8dc4e75644f 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -169,9 +169,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define REG_STACK_SIZE (LAST_STACK_REG - FIRST_STACK_REG + 1)
-/* True if the current function returns a real value. */
-static int current_function_returns_real;
-
/* This is the basic stack record. TOP is an index into REG[] such
that REG[TOP] is the top of stack. If TOP is -1 the stack is empty.
@@ -219,7 +216,11 @@ static HARD_REG_SET *block_out_reg_set;
static int *block_number;
/* This is the register file for all register after conversion */
-static rtx FP_mode_reg[FIRST_PSEUDO_REGISTER][(int) MAX_MACHINE_MODE];
+static rtx
+ FP_mode_reg[LAST_STACK_REG+1-FIRST_STACK_REG][(int) MAX_MACHINE_MODE];
+
+#define FP_MODE_REG(regno,mode) \
+ (FP_mode_reg[(regno)-FIRST_STACK_REG][(int)(mode)])
/* Get the basic block number of an insn. See note at block_number
definition are validity of this information. */
@@ -240,10 +241,55 @@ extern rtx emit_label_after ();
static void find_blocks ();
static uses_reg_or_mem ();
static void stack_reg_life_analysis ();
+static void record_reg_life_pat ();
static void change_stack ();
static void convert_regs ();
static void dump_stack_info ();
+/* Mark all registers needed for this pattern. */
+
+static void
+mark_regs_pat (pat, set)
+ rtx pat;
+ HARD_REG_SET *set;
+{
+ enum machine_mode mode;
+ register int regno;
+ register int count;
+
+ if (GET_CODE (pat) == SUBREG)
+ {
+ mode = GET_MODE (pat);
+ regno = SUBREG_WORD (pat);
+ regno += REGNO (SUBREG_REG (pat));
+ }
+ else
+ regno = REGNO (pat), mode = GET_MODE (pat);
+
+ for (count = HARD_REGNO_NREGS (regno, mode);
+ count; count--, regno++)
+ SET_HARD_REG_BIT (*set, regno);
+}
+
+/* Reorganise the stack into ascending numbers,
+ after this insn. */
+
+static void
+straighten_stack (insn, regstack)
+ rtx insn;
+ stack regstack;
+{
+ struct stack_def temp_stack;
+ int top;
+
+ 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;
+
+ change_stack (insn, regstack, &temp_stack, emit_insn_after);
+}
+
/* Return non-zero if any stack register is mentioned somewhere within PAT. */
int
@@ -293,19 +339,37 @@ reg_to_stack (first, file)
register int i;
int stack_reg_seen = 0;
enum machine_mode mode;
+ HARD_REG_SET stackentry;
- current_function_returns_real
- = TREE_CODE (TREE_TYPE (DECL_RESULT (current_function_decl))) == REAL_TYPE;
+ CLEAR_HARD_REG_SET (stackentry);
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- FP_mode_reg[i][(int) mode] = gen_rtx (REG, mode, i);
+ {
+ static initialised;
+ if (!initialised)
+ {
+#if 0
+ initialised = 1; /* This array can not have been previously
+ initialised, because the rtx's are
+ thrown away between compilations of
+ 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))
+ 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))
+ FP_MODE_REG (i, mode) = gen_rtx (REG, mode, i);
+ }
+ }
+ }
/* Count the basic blocks. Also find maximum insn uid. */
{
register RTX_CODE prev_code = BARRIER;
register RTX_CODE code;
+ register before_function_beg = 1;
max_uid = 0;
blocks = 0;
@@ -327,14 +391,24 @@ reg_to_stack (first, file)
&& GET_RTX_CLASS (code) == 'i'))
blocks++;
+ if (code == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
+ 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. */
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ if (GET_RTX_CLASS (code) == 'i'
&& stack_regs_mentioned_p (PATTERN (insn)))
{
stack_reg_seen = 1;
PUT_MODE (insn, QImode);
+
+ /* Note any register passing parameters. */
+
+ if (before_function_beg && code == INSN
+ && GET_CODE (PATTERN (insn)) == USE)
+ record_reg_life_pat (PATTERN (insn), (HARD_REG_SET*) 0,
+ &stackentry, 1);
}
else
PUT_MODE (insn, VOIDmode);
@@ -373,7 +447,7 @@ reg_to_stack (first, file)
block_number = (int *) alloca ((max_uid + 1) * sizeof (int));
find_blocks (first);
- stack_reg_life_analysis (first);
+ stack_reg_life_analysis (first, &stackentry);
/* Dump the life analysis debug information before jump
optimization, as that will destroy the LABEL_REFS we keep the
@@ -445,13 +519,27 @@ static rtx *
get_true_reg (pat)
rtx *pat;
{
- while (GET_CODE (*pat) == SUBREG
- || GET_CODE (*pat) == FLOAT
- || GET_CODE (*pat) == FIX
- || GET_CODE (*pat) == FLOAT_EXTEND)
- pat = & XEXP (*pat, 0);
-
- return pat;
+ for (;;)
+ 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)))
+ {
+ *pat = FP_MODE_REG (REGNO (subreg) + SUBREG_WORD (*pat),
+ GET_MODE (subreg));
+ default:
+ return pat;
+ }
+ }
+ case FLOAT:
+ case FIX:
+ case FLOAT_EXTEND:
+ pat = & XEXP (*pat, 0);
+ }
}
/* Scan the OPERANDS and OPERAND_CONSTRAINTS of an asm_operands.
@@ -963,34 +1051,36 @@ record_asm_reg_life (insn, regstack, operands, constraints,
This function does not know about SET_DESTs that are both input and
output (such as ZERO_EXTRACT) - this cannot happen on a 387. */
-void
-record_reg_life_pat (pat, src, dest)
+static void
+record_reg_life_pat (pat, src, dest, douse)
rtx pat;
HARD_REG_SET *src, *dest;
+ int douse;
{
register char *fmt;
register int i;
- if (STACK_REG_P (pat))
+ if (STACK_REG_P (pat)
+ || GET_CODE (pat) == SUBREG && STACK_REG_P (SUBREG_REG (pat)))
{
if (src)
- SET_HARD_REG_BIT (*src, REGNO (pat));
+ mark_regs_pat (pat, src);
if (dest)
- SET_HARD_REG_BIT (*dest, REGNO (pat));
+ mark_regs_pat (pat, dest);
return;
}
if (GET_CODE (pat) == SET)
{
- record_reg_life_pat (XEXP (pat, 0), NULL_PTR, dest);
- record_reg_life_pat (XEXP (pat, 1), src, NULL_PTR);
+ record_reg_life_pat (XEXP (pat, 0), NULL_PTR, dest, 0);
+ record_reg_life_pat (XEXP (pat, 1), src, NULL_PTR, 0);
return;
}
/* We don't need to consider either of these cases. */
- if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
+ if (GET_CODE (pat) == USE && !douse || GET_CODE (pat) == CLOBBER)
return;
fmt = GET_RTX_FORMAT (GET_CODE (pat));
@@ -1001,10 +1091,10 @@ record_reg_life_pat (pat, src, dest)
register int j;
for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
- record_reg_life_pat (XVECEXP (pat, i, j), src, dest);
+ record_reg_life_pat (XVECEXP (pat, i, j), src, dest, 0);
}
else if (fmt[i] == 'e')
- record_reg_life_pat (XEXP (pat, i), src, dest);
+ record_reg_life_pat (XEXP (pat, i), src, dest, 0);
}
}
@@ -1094,75 +1184,74 @@ record_reg_life (insn, block, regstack)
return;
}
- /* An insn referencing a stack reg has a mode of QImode. */
- if (GET_MODE (insn) == QImode)
{
HARD_REG_SET src, dest;
int regno;
CLEAR_HARD_REG_SET (src);
CLEAR_HARD_REG_SET (dest);
- record_reg_life_pat (PATTERN (insn), &src, &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, 1);
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][(int) DFmode],
+ 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][(int) DFmode],
+ FP_MODE_REG (regno, DFmode),
REG_NOTES (insn));
}
- AND_COMPL_HARD_REG_SET (regstack->reg_set, dest);
- IOR_HARD_REG_SET (regstack->reg_set, src);
- }
-
- /* 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(). */
-
- if (GET_CODE (insn) == CALL_INSN)
- {
- int reg = FIRST_FLOAT_REG;
-
- /* If a stack reg is mentioned in a CALL_INSN, it must be as the
- return value. */
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ int reg;
- if (stack_regs_mentioned_p (PATTERN (insn)))
- 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(). */
- for (; reg <= LAST_STACK_REG; reg++)
- if (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][(int) DFmode],
- CONST0_RTX (DFmode));
- init = emit_insn_after (pat, insn);
- PUT_MODE (init, QImode);
+ pat = gen_rtx (SET, VOIDmode, FP_MODE_REG (reg, DFmode),
+ CONST0_RTX (DFmode));
+ init = emit_insn_after (pat, insn);
+ PUT_MODE (init, QImode);
- 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 */
+ /* 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, call_used_reg_set);
+ AND_COMPL_HARD_REG_SET (regstack->reg_set, dest);
+ IOR_HARD_REG_SET (regstack->reg_set, src);
}
}
@@ -1311,8 +1400,8 @@ uses_reg_or_mem (x)
/* If current function returns its result in an fp stack register,
return the register number. Otherwise return -1. */
-static int
-stack_result_p (decl)
+static rtx
+stack_result (decl)
tree decl;
{
rtx result = DECL_RTL (DECL_RESULT (decl));
@@ -1329,7 +1418,7 @@ stack_result_p (decl)
#endif
}
- return STACK_REG_P (result) ? REGNO (result) : -1;
+ return STACK_REG_P (result) ? result : (rtx) 0;
}
/* Determine the which registers are live at the start of each basic
@@ -1341,7 +1430,7 @@ stack_result_p (decl)
Then, start with the last block and work back to the first block.
Similarly, work backwards within each block, insn by insn, recording
- which regs are die and which are used (and therefore live) in the
+ which regs are dead and which are used (and therefore live) in the
hard reg set of block_stack_in[].
After processing each basic block, if there is a label at the start
@@ -1363,31 +1452,33 @@ stack_result_p (decl)
done after CALL_INSNs in record_reg_life. */
static void
-stack_reg_life_analysis (first)
+stack_reg_life_analysis (first, stackentry)
rtx first;
+ HARD_REG_SET *stackentry;
{
int reg, block;
struct stack_def regstack;
- if (current_function_returns_real
- && stack_result_p (current_function_decl) >= 0)
- {
- /* Find all RETURN insns and mark them. */
+ {
+ rtx retvalue;
- int value_regno = stack_result_p (current_function_decl);
+ if (retvalue = stack_result (current_function_decl))
+ {
+ /* Find all RETURN insns and mark them. */
- for (block = blocks - 1; block >= 0; block--)
- if (GET_CODE (block_end[block]) == JUMP_INSN
- && GET_CODE (PATTERN (block_end[block])) == RETURN)
- SET_HARD_REG_BIT (block_out_reg_set[block], value_regno);
+ for (block = blocks - 1; --block >= 0;)
+ if (GET_CODE (block_end[block]) == JUMP_INSN
+ && GET_CODE (PATTERN (block_end[block])) == RETURN)
+ mark_regs_pat (retvalue, block_out_reg_set+block);
- /* Mark of the end of last block if we "fall off" the end of the
- function into the epilogue. */
+ /* 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
- || GET_CODE (PATTERN (block_end[blocks-1])) == RETURN)
- SET_HARD_REG_BIT (block_out_reg_set[blocks-1], value_regno);
- }
+ if (GET_CODE (block_end[blocks-1]) != JUMP_INSN
+ || 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 */
@@ -1470,44 +1561,35 @@ stack_reg_life_analysis (first)
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. */
- HARD_REG_SET empty_regs;
- CLEAR_HARD_REG_SET (empty_regs);
- GO_IF_HARD_REG_SUBSET (block_stack_in[0].reg_set, empty_regs,
- no_live_regs);
- }
-
/* Load zero into each live register. The fact that a register
- appears live at the function start does not necessarily imply an error
- in the user program: it merely means that we could not determine that
- there wasn't such an error, just as -Wunused sometimes gives
- "incorrect" warnings. In those cases, these initializations will do
- no harm.
+ appears live at the function start necessarily implies an error
+ in the user program: it means that (unless the offending code is *never*
+ executed) this program is using uninitialised floating point
+ variables. In order to keep broken code like this happy, we initialise
+ those variables with zero.
Note that we are inserting virtual register references here:
these insns must be processed by convert_regs later. Also, these
insns will not be in block_number, so BLOCK_NUM() will fail for them. */
for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; reg--)
- if (TEST_HARD_REG_BIT (block_stack_in[0].reg_set, reg))
+ if (TEST_HARD_REG_BIT (block_stack_in[0].reg_set, reg)
+ && ! TEST_HARD_REG_BIT (*stackentry, reg))
{
rtx init_rtx;
- init_rtx = gen_rtx (SET, VOIDmode, FP_mode_reg[reg][(int) DFmode],
+ init_rtx = gen_rtx (SET, VOIDmode, FP_MODE_REG(reg, DFmode),
CONST0_RTX (DFmode));
block_begin[0] = emit_insn_after (init_rtx, first);
PUT_MODE (block_begin[0], QImode);
CLEAR_HARD_REG_BIT (block_stack_in[0].reg_set, reg);
}
-
- no_live_regs:
- ;
}
/*****************************************************************************
@@ -1527,10 +1609,14 @@ replace_reg (reg, regno)
|| ! STACK_REG_P (*reg))
abort ();
- if (GET_MODE_CLASS (GET_MODE (*reg)) != MODE_FLOAT)
- abort ();
+ switch (GET_MODE_CLASS (GET_MODE (*reg)))
+ {
+ default: abort ();
+ case MODE_FLOAT:
+ case MODE_COMPLEX_FLOAT:;
+ }
- *reg = FP_mode_reg[regno][(int) GET_MODE (*reg)];
+ *reg = FP_MODE_REG (regno, GET_MODE (*reg));
}
/* Remove a note of type NOTE, which must be found, for register
@@ -1614,15 +1700,15 @@ emit_pop_insn (insn, regstack, reg, when)
if (hard_regno < FIRST_STACK_REG)
abort ();
- pop_rtx = gen_rtx (SET, VOIDmode, FP_mode_reg[hard_regno][(int) DFmode],
- FP_mode_reg[FIRST_STACK_REG][(int) 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);
/* ??? This used to be VOIDmode, but that seems wrong. */
PUT_MODE (pop_insn, QImode);
REG_NOTES (pop_insn) = gen_rtx (EXPR_LIST, REG_DEAD,
- FP_mode_reg[FIRST_STACK_REG][(int) DFmode],
+ FP_MODE_REG (FIRST_STACK_REG, DFmode),
REG_NOTES (pop_insn));
regstack->reg[regstack->top - (hard_regno - FIRST_STACK_REG)]
@@ -1706,8 +1792,8 @@ emit_swap_insn (insn, regstack, reg)
abort ();
}
- swap_rtx = gen_swapdf (FP_mode_reg[hard_regno][(int) DFmode],
- FP_mode_reg[FIRST_STACK_REG][(int) DFmode]);
+ swap_rtx = gen_swapdf (FP_MODE_REG (hard_regno, DFmode),
+ FP_MODE_REG (FIRST_STACK_REG, DFmode));
swap_insn = emit_insn_after (swap_rtx, i1);
/* ??? This used to be VOIDmode, but that seems wrong. */
PUT_MODE (swap_insn, QImode);
@@ -1722,47 +1808,50 @@ move_for_stack_reg (insn, regstack, pat)
stack regstack;
rtx pat;
{
- rtx *src = get_true_reg (&SET_SRC (pat));
- rtx *dest = get_true_reg (&SET_DEST (pat));
+ rtx *psrc = get_true_reg (&SET_SRC (pat));
+ rtx *pdest = get_true_reg (&SET_DEST (pat));
+ rtx src, dest;
rtx note;
- if (STACK_REG_P (*src) && STACK_REG_P (*dest))
+ src = *psrc; dest = *pdest;
+
+ if (STACK_REG_P (src) && STACK_REG_P (dest))
{
/* Write from one stack reg to another. If SRC dies here, then
just change the register mapping and delete the insn. */
- note = find_regno_note (insn, REG_DEAD, REGNO (*src));
+ note = find_regno_note (insn, REG_DEAD, REGNO (src));
if (note)
{
int i;
/* If this is a no-op move, there must not be a REG_DEAD note. */
- if (REGNO (*src) == REGNO (*dest))
+ if (REGNO (src) == REGNO (dest))
abort ();
for (i = regstack->top; i >= 0; i--)
- if (regstack->reg[i] == REGNO (*src))
+ if (regstack->reg[i] == REGNO (src))
break;
/* The source must be live, and the dest must be dead. */
- if (i < 0 || get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG)
+ if (i < 0 || get_hard_regnum (regstack, dest) >= FIRST_STACK_REG)
abort ();
/* It is possible that the dest is unused after this insn.
If so, just pop the src. */
- if (find_regno_note (insn, REG_UNUSED, REGNO (*dest)))
+ if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
{
- emit_pop_insn (insn, regstack, *src, emit_insn_after);
+ emit_pop_insn (insn, regstack, src, emit_insn_after);
delete_insn_for_stacker (insn);
return;
}
- regstack->reg[i] = REGNO (*dest);
+ regstack->reg[i] = REGNO (dest);
- SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
- CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src));
+ SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
+ CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));
delete_insn_for_stacker (insn);
@@ -1776,41 +1865,41 @@ move_for_stack_reg (insn, regstack, pat)
it is REG_UNUSED, we must pop the reg now, as per-insn processing
for REG_UNUSED will not work for deleted insns. */
- if (REGNO (*src) == REGNO (*dest))
+ if (REGNO (src) == REGNO (dest))
{
- if (find_regno_note (insn, REG_UNUSED, REGNO (*dest)))
- emit_pop_insn (insn, regstack, *dest, emit_insn_after);
+ if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
+ emit_pop_insn (insn, regstack, dest, emit_insn_after);
delete_insn_for_stacker (insn);
return;
}
/* The destination ought to be dead */
- if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG)
+ if (get_hard_regnum (regstack, dest) >= FIRST_STACK_REG)
abort ();
- replace_reg (src, get_hard_regnum (regstack, *src));
+ replace_reg (psrc, get_hard_regnum (regstack, src));
- regstack->reg[++regstack->top] = REGNO (*dest);
- SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
- replace_reg (dest, FIRST_STACK_REG);
+ regstack->reg[++regstack->top] = REGNO (dest);
+ SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
+ replace_reg (pdest, FIRST_STACK_REG);
}
- else if (STACK_REG_P (*src))
+ else if (STACK_REG_P (src))
{
/* Save from a stack reg to MEM, or possibly integer reg. Since
only top of stack may be saved, emit an exchange first if
needs be. */
- emit_swap_insn (insn, regstack, *src);
+ emit_swap_insn (insn, regstack, src);
- note = find_regno_note (insn, REG_DEAD, REGNO (*src));
+ note = find_regno_note (insn, REG_DEAD, REGNO (src));
if (note)
{
replace_reg (&XEXP (note, 0), FIRST_STACK_REG);
regstack->top--;
- CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src));
+ CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));
}
- else if (GET_MODE (*src) == XFmode && regstack->top != REG_STACK_SIZE)
+ else if (GET_MODE (src) == XFmode && regstack->top != REG_STACK_SIZE)
{
/* A 387 cannot write an XFmode value to a MEM without
clobbering the source reg. The output code can handle
@@ -1820,7 +1909,7 @@ move_for_stack_reg (insn, regstack, pat)
stack is not full, and then write the value to memory via
a pop. */
rtx push_rtx, push_insn;
- rtx top_stack_reg = FP_mode_reg[FIRST_STACK_REG][(int) XFmode];
+ rtx top_stack_reg = FP_MODE_REG (FIRST_STACK_REG, XFmode);
push_rtx = gen_movxf (top_stack_reg, top_stack_reg);
push_insn = emit_insn_before (push_rtx, insn);
@@ -1829,9 +1918,9 @@ move_for_stack_reg (insn, regstack, pat)
REG_NOTES (insn));
}
- replace_reg (src, FIRST_STACK_REG);
+ replace_reg (psrc, FIRST_STACK_REG);
}
- else if (STACK_REG_P (*dest))
+ else if (STACK_REG_P (dest))
{
/* Load from MEM, or possibly integer REG or constant, into the
stack regs. The actual target is always the top of the
@@ -1839,15 +1928,15 @@ move_for_stack_reg (insn, regstack, pat)
now at top of stack. */
/* The destination ought to be dead */
- if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG)
+ if (get_hard_regnum (regstack, dest) >= FIRST_STACK_REG)
abort ();
if (regstack->top >= REG_STACK_SIZE)
abort ();
- regstack->reg[++regstack->top] = REGNO (*dest);
- SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
- replace_reg (dest, FIRST_STACK_REG);
+ regstack->reg[++regstack->top] = REGNO (dest);
+ SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
+ replace_reg (pdest, FIRST_STACK_REG);
}
else
abort ();
@@ -2019,8 +2108,15 @@ subst_stack_regs_pat (insn, regstack, pat)
break;
case CALL:
- regstack->reg[++regstack->top] = REGNO (*dest);
- SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+ {
+ 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;
@@ -2422,7 +2518,7 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
that these regs can't be MODE_INT and will abort. Just put
the right reg there without calling replace_reg. */
- *clobber_loc[i] = FP_mode_reg[regnum][(int) DFmode];
+ *clobber_loc[i] = FP_MODE_REG (regnum, DFmode);
}
}
@@ -2524,16 +2620,27 @@ subst_stack_regs (insn, regstack)
register int i;
int n_operands;
- if ((GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
- || INSN_DELETED_P (insn))
- return;
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ int top = regstack->top;
- /* The stack should be empty at a call. */
+ /* If there are any floating point parameters to be passed in
+ registers for this call, make sure they are in the right
+ order. */
- if (GET_CODE (insn) == CALL_INSN)
- for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
- if (TEST_HARD_REG_BIT (regstack->reg_set, i))
- abort ();
+ if (top >= 0)
+ {
+ straighten_stack (PREV_INSN (insn), regstack);
+
+ /* 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--;
+ }
+ }
+ }
/* Do the actual substitution if any stack regs are mentioned.
Since we only record whether entire insn mentions stack regs, and
@@ -2630,7 +2737,7 @@ change_stack (insn, old, new, when)
for (reg = old->top; reg >= 0; reg--)
if (! TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]))
- emit_pop_insn (insn, old, FP_mode_reg[old->reg[reg]][(int) DFmode],
+ emit_pop_insn (insn, old, FP_MODE_REG (old->reg[reg], DFmode),
emit_insn_before);
if (new->top == -2)
@@ -2680,7 +2787,7 @@ change_stack (insn, old, new, when)
abort ();
emit_swap_insn (insn, old,
- FP_mode_reg[old->reg[reg]][(int) DFmode]);
+ FP_MODE_REG (old->reg[reg], DFmode));
}
/* See if any regs remain incorrect. If so, bring an
@@ -2691,7 +2798,7 @@ change_stack (insn, old, new, when)
if (new->reg[reg] != old->reg[reg])
{
emit_swap_insn (insn, old,
- FP_mode_reg[old->reg[reg]][(int) DFmode]);
+ FP_MODE_REG (old->reg[reg], DFmode));
break;
}
} while (reg >= 0);
@@ -2727,8 +2834,13 @@ goto_block_pat (insn, regstack, pat)
struct stack_def temp_stack;
int reg;
- if (GET_CODE (pat) != LABEL_REF)
- {
+ switch (GET_CODE (pat))
+ {
+ case RETURN:
+ straighten_stack (PREV_INSN (insn), regstack);
+ return;
+ default:
+ {
int i, j;
char *fmt = GET_RTX_FORMAT (GET_CODE (pat));
@@ -2741,7 +2853,9 @@ goto_block_pat (insn, regstack, pat)
goto_block_pat (insn, regstack, XVECEXP (pat, i, j));
}
return;
- }
+ }
+ case LABEL_REF:;
+ }
label = XEXP (pat, 0);
if (GET_CODE (label) != CODE_LABEL)
@@ -2858,10 +2972,8 @@ convert_regs ()
next = NEXT_INSN (insn);
/* Don't bother processing unless there is a stack reg
- mentioned.
-
- ??? For now, process CALL_INSNs too to make sure that the
- stack regs are dead after a call. Remove this eventually. */
+ mentioned or if it's a CALL_INSN (register passing of
+ floating point values). */
if (GET_MODE (insn) == QImode || GET_CODE (insn) == CALL_INSN)
subst_stack_regs (insn, &regstack);
@@ -2895,12 +3007,27 @@ 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. */
- for (reg = regstack.top; reg >= 0; reg--)
- if (! current_function_returns_real
- || regstack.reg[reg] != FIRST_STACK_REG)
- insn = emit_pop_insn (insn, &regstack,
- FP_mode_reg[regstack.reg[reg]][(int) DFmode],
+ {
+ 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);
+ }
+ straighten_stack (insn, &regstack);
}
/* Check expression PAT, which is in INSN, for label references. if
@@ -2974,14 +3101,14 @@ dump_stack_info (file)
fprintf (file, " previous");
fprintf (file, "\nlive stack registers on block entry: ");
- for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG ; regno++)
+ for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)
{
if (TEST_HARD_REG_BIT (block_stack_in[block].reg_set, regno))
fprintf (file, "%d ", regno);
}
fprintf (file, "\nlive stack registers on block exit: ");
- for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG ; regno++)
+ for (regno = FIRST_STACK_REG; regno <= LAST_STACK_REG; regno++)
{
if (TEST_HARD_REG_BIT (block_out_reg_set[block], regno))
fprintf (file, "%d ", regno);