int
stack_regs_mentioned_p (pat)
- register rtx pat;
+ rtx pat;
{
register char *fmt;
register int i;
return pat;
}
-
-/* If REG is a stack register that is marked dead in REGSTACK, then
- record that it is now live. If REG is not DEST, add a death note to
- INSN if there isn't one already. If DEST is not a reg, it is safe to
- assume that it does not mention a reg anywhere within. */
-
-static void
-record_note_if_dead (insn, regstack, reg, dest)
- rtx insn;
- stack regstack;
- rtx reg, dest;
-{
- reg = * get_true_reg (& reg);
-
- if (STACK_REG_P (reg))
- {
- if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (reg)))
- {
- if ((! REG_P (dest) || REGNO (dest) != REGNO (reg))
- && ! find_regno_note (insn, REG_DEAD, REGNO (reg)))
- REG_NOTES (insn) = gen_rtx (EXPR_LIST,
- REG_DEAD, reg, REG_NOTES (insn));
-
- SET_HARD_REG_BIT (regstack->reg_set, REGNO (reg));
- }
- }
- else
- if (stack_regs_mentioned_p (reg))
- abort ();
-}
\f
/* Scan the OPERANDS and OPERAND_CONSTRAINTS of an asm_operands.
N_OPERANDS is the total number of operands. Return which alternative
rtx *clobber_reg;
- /* Find out what the constraints required. If no constraint
+ /* Find out what the constraints require. If no constraint
alternative matches, that is a compiler bug: we should have caught
such an insn during reload. */
i = constrain_asm_operands (n_operands, operands, constraints,
}
}
-/* Scan PAT, which is part of INSN, and record the life & death of
- stack registers in REGSTACK. If a register was dead, but is an input
- operand in this insn, then mark the register live and record a death
- note.
-
- If a register is dead after this insn, but is an output operand in
- this insn, record a REG_UNUSED note.
+/* Scan PAT, which is part of INSN, and record registers appearing in
+ a SET_DEST in DEST, and other registers in SRC.
This function does not know about SET_DESTs that are both input and
output (such as ZERO_EXTRACT) - this cannot happen on a 387. */
-static void
-record_reg_life_pat (insn, regstack, pat)
- rtx insn;
- stack regstack;
+void
+record_reg_life_pat (pat, src, dest)
rtx pat;
+ HARD_REG_SET *src, *dest;
{
- rtx src, dest;
-
- /* We should have already handled any asm. */
- if (GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ASM_OPERANDS)
- abort ();
-
- if (GET_CODE (pat) != SET)
- return;
-
- dest = * get_true_reg (& SET_DEST (pat));
-
- /* The destination is dead before this insn. If the destination is
- not used after this insn, record this with REG_UNUSED. */
+ register char *fmt;
+ register int i;
- if (STACK_REG_P (dest))
+ if (STACK_REG_P (pat))
{
- /* ??? This check is unnecessary. */
+ if (src)
+ SET_HARD_REG_BIT (*src, REGNO (pat));
- if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
- abort ();
+ if (dest)
+ SET_HARD_REG_BIT (*dest, REGNO (pat));
- if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (dest)))
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_UNUSED, dest,
- REG_NOTES (insn));
-
- CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
+ return;
}
- else
- if (dest != cc0_rtx && stack_regs_mentioned_p (dest))
- abort ();
-
- src = * get_true_reg (& SET_SRC (pat));
- switch (GET_CODE (src))
+ if (GET_CODE (pat) == SET)
{
- /* ??? get_true_reg will make some of these cases redundant. */
-
- case PLUS:
- case MINUS:
- case MULT:
- case DIV:
- case COMPARE:
- record_note_if_dead (insn, regstack, XEXP (src, 0), dest);
- record_note_if_dead (insn, regstack, XEXP (src, 1), dest);
- break;
-
- case ABS:
- case NEG:
- case SQRT:
- case FLOAT_EXTEND:
- case FLOAT_TRUNCATE:
- case FLOAT:
- case UNSIGNED_FLOAT:
- record_note_if_dead (insn, regstack, XEXP (src, 0), dest);
- break;
-
- case UNSIGNED_FIX:
- case FIX:
- src = XEXP (src, 0);
- if (GET_CODE (src) == FIX)
- record_note_if_dead (insn, regstack, XEXP (src, 0), dest);
- else
- record_note_if_dead (insn, regstack, src, dest);
- break;
-
- case ASM_OPERANDS:
- case ASM_INPUT:
- abort (); /* we should have caught this already. */
- break;
+ record_reg_life_pat (XEXP (pat, 0), NULL_PTR, dest);
+ record_reg_life_pat (XEXP (pat, 1), src, NULL_PTR);
+ return;
+ }
- case REG:
- record_note_if_dead (insn, regstack, src, dest);
- break;
+ /* We don't need to consider either of these cases. */
+ if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER)
+ return;
- default:
- /* If a stack register appears in the src RTL, it is a bug, and
- code should be added above to handle it. */
+ 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;
- if (stack_regs_mentioned_p (src))
- abort ();
+ for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
+ record_reg_life_pat (XVECEXP (pat, i, j), src, dest);
+ }
+ else if (fmt[i] == 'e')
+ record_reg_life_pat (XEXP (pat, i), src, dest);
}
}
\f
return;
}
- if (GET_CODE (PATTERN (insn)) == PARALLEL)
+ /* An insn referencing a stack reg has a mode of QImode. */
+ if (GET_MODE (insn) == QImode)
{
- register int i;
+ 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);
- for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
- record_reg_life_pat (insn, regstack, XVECEXP (PATTERN (insn), 0, i));
+ 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],
+ REG_NOTES (insn));
+ else if (TEST_HARD_REG_BIT (dest, regno)
+ && ! TEST_HARD_REG_BIT (src, regno))
+ REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_UNUSED,
+ FP_mode_reg[regno][(int) DFmode],
+ REG_NOTES (insn));
+ }
+
+ AND_COMPL_HARD_REG_SET (regstack->reg_set, dest);
+ IOR_HARD_REG_SET (regstack->reg_set, src);
}
- else if (GET_MODE (insn) == QImode)
- record_reg_life_pat (insn, regstack, PATTERN (insn));
/* 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
int reg = FIRST_FLOAT_REG;
/* If a stack reg is mentioned in a CALL_INSN, it must be as the
- return value; conversely, if a float is returned, a stack reg
- must be mentioned. */
+ return value. */
if (stack_regs_mentioned_p (PATTERN (insn)))
reg++;
int reg, block;
struct stack_def regstack;
- if (current_function_returns_real)
+ if (current_function_returns_real
+ && STACK_REG_P (DECL_RTL (DECL_RESULT (current_function_decl))))
{
/* Find all RETURN insns and mark them. */
+ int value_regno = REGNO (DECL_RTL (DECL_RESULT (current_function_decl)));
+
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], FIRST_STACK_REG);
+ SET_HARD_REG_BIT (block_out_reg_set[block], value_regno);
/* Mark of 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], FIRST_STACK_REG);
+ SET_HARD_REG_BIT (block_out_reg_set[blocks-1], value_regno);
}
/* now scan all blocks backward for stack register use */
break;
+ case UNSPEC:
+ switch (XINT (SET_SRC (pat), 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));
+
+ emit_swap_insn (insn, regstack, *src1, emit_insn_before);
+
+ src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+
+ if (STACK_REG_P (*dest))
+ replace_reg (dest, FIRST_STACK_REG);
+
+ if (src1_note)
+ {
+ replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+ regstack->top--;
+ CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1));
+ }
+
+ replace_reg (src1, FIRST_STACK_REG);
+
+ break;
+
+ default:
+ abort ();
+ }
+ break;
+
default:
abort ();
}