/* Register to Stack convert for GNU compiler.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
static void emit_swap_insn (rtx, stack, rtx);
static void swap_to_top(rtx, stack, rtx, rtx);
static bool move_for_stack_reg (rtx, stack, rtx);
+static bool move_nan_for_stack_reg (rtx, stack, rtx);
static int swap_rtx_condition_1 (rtx);
static int swap_rtx_condition (rtx);
static void compare_for_stack_reg (rtx, stack, rtx);
if (regstack->reg[i] == REGNO (src))
break;
- /* The source must be live, and the dest must be dead. */
- gcc_assert (i >= 0);
+ /* The destination must be dead, or life analysis is borked. */
gcc_assert (get_hard_regnum (regstack, dest) < FIRST_STACK_REG);
+ /* If the source is not live, this is yet another case of
+ uninitialized variables. Load up a NaN instead. */
+ if (i < 0)
+ return move_nan_for_stack_reg (insn, regstack, dest);
+
/* It is possible that the dest is unused after this insn.
If so, just pop the src. */
available. Push the source value here if the register
stack is not full, and then write the value to memory via
a pop. */
- rtx push_rtx, push_insn;
+ rtx push_rtx;
rtx top_stack_reg = FP_MODE_REG (FIRST_STACK_REG, GET_MODE (src));
push_rtx = gen_movxf (top_stack_reg, top_stack_reg);
- push_insn = emit_insn_before (push_rtx, insn);
+ emit_insn_before (push_rtx, insn);
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, top_stack_reg,
REG_NOTES (insn));
}
return control_flow_insn_deleted;
}
+
+/* A helper function which replaces INSN with a pattern that loads up
+ a NaN into DEST, then invokes move_for_stack_reg. */
+
+static bool
+move_nan_for_stack_reg (rtx insn, stack regstack, rtx dest)
+{
+ rtx pat;
+
+ dest = FP_MODE_REG (REGNO (dest), SFmode);
+ pat = gen_rtx_SET (VOIDmode, dest, not_a_num);
+ PATTERN (insn) = pat;
+ INSN_CODE (insn) = -1;
+
+ return move_for_stack_reg (insn, regstack, pat);
+}
\f
/* 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
{
rtx *src1, *src2;
rtx src1_note, src2_note;
- rtx flags_user;
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. */
all other clobbers, this must be due to a function
returning without a value. Load up a NaN. */
- if (! note
- && get_hard_regnum (regstack, *dest) == -1)
- {
- pat = gen_rtx_SET (VOIDmode,
- FP_MODE_REG (REGNO (*dest), SFmode),
- not_a_num);
- PATTERN (insn) = pat;
- control_flow_insn_deleted |= move_for_stack_reg (insn, regstack, pat);
- }
- if (! note && COMPLEX_MODE_P (GET_MODE (*dest))
- && get_hard_regnum (regstack, FP_MODE_REG (REGNO (*dest), DFmode)) == -1)
+ if (!note)
{
- pat = gen_rtx_SET (VOIDmode,
- FP_MODE_REG (REGNO (*dest) + 1, SFmode),
- not_a_num);
- PATTERN (insn) = pat;
- control_flow_insn_deleted |= move_for_stack_reg (insn, regstack, pat);
+ rtx t = *dest;
+ if (get_hard_regnum (regstack, t) == -1)
+ control_flow_insn_deleted
+ |= move_nan_for_stack_reg (insn, regstack, t);
+ if (COMPLEX_MODE_P (GET_MODE (t)))
+ {
+ t = FP_MODE_REG (REGNO (t) + 1, DFmode);
+ if (get_hard_regnum (regstack, t) == -1)
+ control_flow_insn_deleted
+ |= move_nan_for_stack_reg (insn, regstack, t);
+ }
}
}
}
/* Pop any registers that are not needed in the new block. */
- 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], DFmode),
- EMIT_BEFORE);
+ /* If the destination block's stack already has a specified layout
+ and contains two or more registers, use a more intelligent algorithm
+ to pop registers that minimizes the number number of fxchs below. */
+ if (new->top > 0)
+ {
+ bool slots[REG_STACK_SIZE];
+ int pops[REG_STACK_SIZE];
+ int next, dest, topsrc;
+
+ /* First pass to determine the free slots. */
+ for (reg = 0; reg <= new->top; reg++)
+ slots[reg] = TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]);
+
+ /* Second pass to allocate preferred slots. */
+ topsrc = -1;
+ for (reg = old->top; reg > new->top; reg--)
+ if (TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]))
+ {
+ dest = -1;
+ for (next = 0; next <= new->top; next++)
+ if (!slots[next] && new->reg[next] == old->reg[reg])
+ {
+ /* If this is a preference for the new top of stack, record
+ the fact by remembering it's old->reg in topsrc. */
+ if (next == new->top)
+ topsrc = reg;
+ slots[next] = true;
+ dest = next;
+ break;
+ }
+ pops[reg] = dest;
+ }
+ else
+ pops[reg] = reg;
+
+ /* Intentionally, avoid placing the top of stack in it's correct
+ location, if we still need to permute the stack below and we
+ can usefully place it somewhere else. This is the case if any
+ slot is still unallocated, in which case we should place the
+ top of stack there. */
+ if (topsrc != -1)
+ for (reg = 0; reg < new->top; reg++)
+ if (!slots[reg])
+ {
+ pops[topsrc] = reg;
+ slots[new->top] = false;
+ slots[reg] = true;
+ break;
+ }
+
+ /* Third pass allocates remaining slots and emits pop insns. */
+ next = new->top;
+ for (reg = old->top; reg > new->top; reg--)
+ {
+ dest = pops[reg];
+ if (dest == -1)
+ {
+ /* Find next free slot. */
+ while (slots[next])
+ next--;
+ dest = next--;
+ }
+ emit_pop_insn (insn, old, FP_MODE_REG (old->reg[dest], DFmode),
+ EMIT_BEFORE);
+ }
+ }
+ else
+ {
+ /* The following loop attempts to maximize the number of times we
+ pop the top of the stack, as this permits the use of the faster
+ ffreep instruction on platforms that support it. */
+ int live, next;
+
+ live = 0;
+ for (reg = 0; reg <= old->top; reg++)
+ if (TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]))
+ live++;
+
+ next = live;
+ while (old->top >= live)
+ if (TEST_HARD_REG_BIT (new->reg_set, old->reg[old->top]))
+ {
+ while (TEST_HARD_REG_BIT (new->reg_set, old->reg[next]))
+ next--;
+ emit_pop_insn (insn, old, FP_MODE_REG (old->reg[next], DFmode),
+ EMIT_BEFORE);
+ }
+ else
+ emit_pop_insn (insn, old, FP_MODE_REG (old->reg[old->top], DFmode),
+ EMIT_BEFORE);
+ }
if (new->top == -2)
{
{
struct stack_def regstack;
block_info bi = BLOCK_INFO (block);
- int deleted, inserted, reg;
+ int inserted, reg;
rtx insn, next;
edge e, beste = NULL;
bool control_flow_insn_deleted = false;
edge_iterator ei;
inserted = 0;
- deleted = 0;
any_malformed_asm = false;
/* Find the edge we will copy stack from. It should be the most frequent
rtx set;
if (file)
- {
- fprintf (file, "Emitting insn initializing reg %d\n",
- reg);
- }
+ fprintf (file, "Emitting insn initializing reg %d\n", reg);
- set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode),
- not_a_num);
+ set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode), not_a_num);
insn = emit_insn_after (set, insn);
control_flow_insn_deleted |= subst_stack_regs (insn, ®stack);
}
}
while (sp != stack);
+ free (stack);
+
return inserted;
}