/* Register to Stack convert for GNU compiler.
- Copyright (C) 1992-2017 Free Software Foundation, Inc.
+ Copyright (C) 1992-2019 Free Software Foundation, Inc.
This file is part of GCC.
#include "df.h"
#include "insn-config.h"
#include "memmodel.h"
+#include "regs.h"
#include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */
#include "recog.h"
#include "varasm.h"
static bool move_nan_for_stack_reg (rtx_insn *, stack_ptr, rtx);
static int swap_rtx_condition_1 (rtx);
static int swap_rtx_condition (rtx_insn *);
-static void compare_for_stack_reg (rtx_insn *, stack_ptr, rtx);
+static void compare_for_stack_reg (rtx_insn *, stack_ptr, rtx, bool);
static bool subst_stack_regs_pat (rtx_insn *, stack_ptr, rtx);
static void subst_asm_stack_regs (rtx_insn *, stack_ptr);
static bool subst_stack_regs (rtx_insn *, stack_ptr);
/* Eliminate FP subregister accesses in favor of the
actual FP register in use. */
{
- rtx subreg;
- if (STACK_REG_P (subreg = SUBREG_REG (*pat)))
+ rtx subreg = SUBREG_REG (*pat);
+
+ if (STACK_REG_P (subreg))
{
int regno_off = subreg_regno_offset (REGNO (subreg),
GET_MODE (subreg),
pat = &XEXP (*pat, 0);
break;
}
+
+ case FLOAT_TRUNCATE:
+ if (!flag_unsafe_math_optimizations)
+ return pat;
+ /* FALLTHRU */
+
case FLOAT:
case FIX:
case FLOAT_EXTEND:
pat = &XVECEXP (*pat, 0, 0);
return pat;
- case FLOAT_TRUNCATE:
- if (!flag_unsafe_math_optimizations)
- return pat;
- pat = &XEXP (*pat, 0);
- break;
-
default:
return pat;
}
for (j = 0; j < n_clobbers; j++)
if (REGNO (recog_data.operand[i]) == REGNO (clobber_reg[j]))
{
- error_for_asm (insn, "output constraint %d cannot be specified together with \"%s\" clobber",
+ error_for_asm (insn, "output constraint %d cannot be "
+ "specified together with %qs clobber",
i, reg_names [REGNO (clobber_reg[j])]);
malformed_asm = 1;
break;
if (i != LAST_STACK_REG + 1)
{
- error_for_asm (insn, "output regs must be grouped at top of stack");
+ error_for_asm (insn, "output registers must be grouped at top of stack");
malformed_asm = 1;
}
if (i != LAST_STACK_REG + 1)
{
error_for_asm (insn,
- "implicitly popped regs must be grouped at top of stack");
+ "implicitly popped registers must be grouped "
+ "at top of stack");
malformed_asm = 1;
}
if (i != LAST_STACK_REG + 1)
{
error_for_asm (insn,
- "explicitly used regs must be grouped at top of stack");
+ "explicitly used registers must be grouped "
+ "at top of stack");
malformed_asm = 1;
}
gcc_assert (IN_RANGE (regno, FIRST_STACK_REG, LAST_STACK_REG));
gcc_assert (STACK_REG_P (*reg));
- gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (*reg))
+ gcc_assert (GET_MODE_CLASS (GET_MODE (*reg)) == MODE_FLOAT
|| GET_MODE_CLASS (GET_MODE (*reg)) == MODE_COMPLEX_FLOAT);
*reg = FP_MODE_REG (regno, GET_MODE (*reg));
cases the movdf pattern to pop. */
static rtx_insn *
-emit_pop_insn (rtx_insn *insn, stack_ptr regstack, rtx reg, enum emit_where where)
+emit_pop_insn (rtx_insn *insn, stack_ptr regstack, rtx reg,
+ enum emit_where where)
{
+ machine_mode raw_mode = reg_raw_mode[FIRST_STACK_REG];
rtx_insn *pop_insn;
rtx pop_rtx;
int hard_regno;
CLOBBER and USE expressions. */
if (COMPLEX_MODE_P (GET_MODE (reg)))
{
- rtx reg1 = FP_MODE_REG (REGNO (reg), DFmode);
- rtx reg2 = FP_MODE_REG (REGNO (reg) + 1, DFmode);
+ rtx reg1 = FP_MODE_REG (REGNO (reg), raw_mode);
+ rtx reg2 = FP_MODE_REG (REGNO (reg) + 1, raw_mode);
pop_insn = NULL;
if (get_hard_regnum (regstack, reg1) >= 0)
gcc_assert (hard_regno >= FIRST_STACK_REG);
- pop_rtx = gen_rtx_SET (FP_MODE_REG (hard_regno, DFmode),
- FP_MODE_REG (FIRST_STACK_REG, DFmode));
+ pop_rtx = gen_rtx_SET (FP_MODE_REG (hard_regno, raw_mode),
+ FP_MODE_REG (FIRST_STACK_REG, raw_mode));
if (where == EMIT_AFTER)
pop_insn = emit_insn_after (pop_rtx, insn);
else
pop_insn = emit_insn_before (pop_rtx, insn);
- add_reg_note (pop_insn, REG_DEAD, FP_MODE_REG (FIRST_STACK_REG, DFmode));
+ add_reg_note (pop_insn, REG_DEAD, FP_MODE_REG (FIRST_STACK_REG, raw_mode));
regstack->reg[regstack->top - (hard_regno - FIRST_STACK_REG)]
= regstack->reg[regstack->top];
emit_swap_insn (rtx_insn *insn, stack_ptr regstack, rtx reg)
{
int hard_regno;
- rtx swap_rtx;
int other_reg; /* swap regno temps */
rtx_insn *i1; /* the stack-reg insn prior to INSN */
rtx i1set = NULL_RTX; /* the SET rtx within I1 */
return;
}
- swap_rtx = gen_swapxf (FP_MODE_REG (hard_regno, XFmode),
- FP_MODE_REG (FIRST_STACK_REG, XFmode));
-
+ machine_mode raw_mode = reg_raw_mode[FIRST_STACK_REG];
+ rtx op1 = FP_MODE_REG (hard_regno, raw_mode);
+ rtx op2 = FP_MODE_REG (FIRST_STACK_REG, raw_mode);
+ rtx swap_rtx
+ = gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2, gen_rtx_SET (op1, op2),
+ gen_rtx_SET (op2, op1)));
if (i1)
emit_insn_after (swap_rtx, i1);
else if (current_block)
}
/* The destination ought to be dead. */
- gcc_assert (get_hard_regnum (regstack, dest) < FIRST_STACK_REG);
-
- replace_reg (psrc, get_hard_regnum (regstack, src));
+ if (get_hard_regnum (regstack, dest) >= FIRST_STACK_REG)
+ gcc_assert (any_malformed_asm);
+ else
+ {
+ 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 (pdest, 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))
{
&& XINT (SET_SRC (XVECEXP (pat, 0, 1)), 1) == UNSPEC_TAN)
emit_swap_insn (insn, regstack, dest);
else
- gcc_assert (get_hard_regnum (regstack, dest) < FIRST_STACK_REG);
+ gcc_assert (get_hard_regnum (regstack, dest) < FIRST_STACK_REG
+ || any_malformed_asm);
gcc_assert (regstack->top < REG_STACK_SIZE);
set up. */
static void
-compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx pat_src)
+compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack,
+ rtx pat_src, bool can_pop_second_op)
{
rtx *src1, *src2;
rtx src1_note, src2_note;
if (src1_note)
{
- pop_stack (regstack, REGNO (XEXP (src1_note, 0)));
- replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+ if (*src2 == CONST0_RTX (GET_MODE (*src2)))
+ {
+ /* This is `ftst' insn that can't pop register. */
+ remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src1_note, 0)));
+ emit_pop_insn (insn, regstack, XEXP (src1_note, 0),
+ EMIT_AFTER);
+ }
+ else
+ {
+ pop_stack (regstack, REGNO (XEXP (src1_note, 0)));
+ replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+ }
}
/* If the second operand dies, handle that. But if the operands are
at top (FIRST_STACK_REG) now. */
if (get_hard_regnum (regstack, XEXP (src2_note, 0)) == FIRST_STACK_REG
- && src1_note)
+ && src1_note && can_pop_second_op)
{
pop_stack (regstack, REGNO (XEXP (src2_note, 0)));
replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG + 1);
switch (GET_CODE (pat_src))
{
- case COMPARE:
- compare_for_stack_reg (insn, regstack, pat_src);
- break;
-
case CALL:
{
int count;
case UNSPEC_FRNDINT_FLOOR:
case UNSPEC_FRNDINT_CEIL:
case UNSPEC_FRNDINT_TRUNC:
- case UNSPEC_FRNDINT_MASK_PM:
/* Above insns operate on the top of the stack. */
replace_reg (src2, FIRST_STACK_REG + 1);
break;
- case UNSPEC_SAHF:
- /* (unspec [(unspec [(compare)] UNSPEC_FNSTSW)] UNSPEC_SAHF)
- The combination matches the PPRO fcomi instruction. */
-
- pat_src = XVECEXP (pat_src, 0, 0);
- gcc_assert (GET_CODE (pat_src) == UNSPEC);
- gcc_assert (XINT (pat_src, 1) == UNSPEC_FNSTSW);
- /* Fall through. */
-
case UNSPEC_FNSTSW:
/* 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);
- gcc_assert (GET_CODE (pat_src) == COMPARE);
+ if (GET_CODE (pat_src) == COMPARE)
+ goto do_compare;
- compare_for_stack_reg (insn, regstack, pat_src);
- break;
+ /* Fall through. */
+
+ case UNSPEC_NOTRAP:
+
+ pat_src = XVECEXP (pat_src, 0, 0);
+ gcc_assert (GET_CODE (pat_src) == COMPARE);
+ goto do_compare;
default:
gcc_unreachable ();
}
break;
+ case COMPARE:
+ do_compare:
+ /* `fcomi' insn can't pop two regs. */
+ compare_for_stack_reg (insn, regstack, pat_src,
+ REGNO (*dest) != FLAGS_REG);
+ break;
+
case IF_THEN_ELSE:
/* This insn requires the top of stack to be the destination. */
int regnum = get_hard_regnum (regstack, clobber_reg[i]);
if (regnum >= 0)
- {
- /* Sigh - clobbers always have QImode. But replace_reg knows
- that these regs can't be MODE_INT and will assert. Just put
- the right reg there without calling replace_reg. */
-
- *clobber_loc[i] = FP_MODE_REG (regnum, DFmode);
- }
+ replace_reg (clobber_loc[i], regnum);
}
/* Now remove from REGSTACK any inputs that the asm implicitly popped. */
enum emit_where where)
{
int reg;
- int update_end = 0;
+ machine_mode raw_mode = reg_raw_mode[FIRST_STACK_REG];
+ rtx_insn *update_end = NULL;
int i;
/* Stack adjustments for the first insn in a block update the
if (where == EMIT_AFTER)
{
if (current_block && BB_END (current_block) == insn)
- update_end = 1;
+ update_end = insn;
insn = NEXT_INSN (insn);
}
next--;
dest = next--;
}
- emit_pop_insn (insn, old, FP_MODE_REG (old->reg[dest], DFmode),
+ emit_pop_insn (insn, old, FP_MODE_REG (old->reg[dest], raw_mode),
EMIT_BEFORE);
}
}
{
while (TEST_HARD_REG_BIT (new_stack->reg_set, old->reg[next]))
next--;
- emit_pop_insn (insn, old, FP_MODE_REG (old->reg[next], DFmode),
+ emit_pop_insn (insn, old, FP_MODE_REG (old->reg[next], raw_mode),
EMIT_BEFORE);
}
else
- emit_pop_insn (insn, old, FP_MODE_REG (old->reg[old->top], DFmode),
+ emit_pop_insn (insn, old, FP_MODE_REG (old->reg[old->top], raw_mode),
EMIT_BEFORE);
}
gcc_assert (reg != -1);
emit_swap_insn (insn, old,
- FP_MODE_REG (old->reg[reg], DFmode));
+ FP_MODE_REG (old->reg[reg], raw_mode));
}
/* See if any regs remain incorrect. If so, bring an
if (new_stack->reg[reg] != old->reg[reg])
{
emit_swap_insn (insn, old,
- FP_MODE_REG (old->reg[reg], DFmode));
+ FP_MODE_REG (old->reg[reg], raw_mode));
break;
}
} while (reg >= 0);
}
if (update_end)
- BB_END (current_block) = PREV_INSN (insn);
+ {
+ for (update_end = NEXT_INSN (update_end); update_end != insn;
+ update_end = NEXT_INSN (update_end))
+ {
+ set_block_for_insn (update_end, current_block);
+ if (INSN_P (update_end))
+ df_insn_rescan (update_end);
+ }
+ BB_END (current_block) = PREV_INSN (insn);
+ }
}
\f
/* Print stack configuration. */
if (!e1)
return e2;
- if (EDGE_FREQUENCY (e1) > EDGE_FREQUENCY (e2))
- return e1;
- if (EDGE_FREQUENCY (e1) < EDGE_FREQUENCY (e2))
- return e2;
-
- if (e1->count > e2->count)
+ if (e1->count () > e2->count ())
return e1;
- if (e1->count < e2->count)
+ if (e1->count () < e2->count ())
return e2;
/* Prefer critical edges to minimize inserting compensation code on
/* Don't bother processing unless there is a stack reg
mentioned or if it's a CALL_INSN. */
- if (DEBUG_INSN_P (insn))
+ if (DEBUG_BIND_INSN_P (insn))
{
if (starting_stack_p)
debug_insns_with_starting_stack++;
for (insn = BB_HEAD (block); debug_insns_with_starting_stack;
insn = NEXT_INSN (insn))
{
- if (!DEBUG_INSN_P (insn))
+ if (!DEBUG_BIND_INSN_P (insn))
continue;
debug_insns_with_starting_stack--;