/* Register to Stack convert for GNU compiler.
- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
- Free Software Foundation, Inc.
+ Copyright (C) 1992-2016 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
+#include "backend.h"
+#include "target.h"
#include "rtl.h"
-#include "tm_p.h"
-#include "function.h"
+#include "tree.h"
+#include "df.h"
#include "insn-config.h"
-#include "regs.h"
-#include "hard-reg-set.h"
-#include "flags.h"
-#include "toplev.h"
+#include "emit-rtl.h" /* FIXME: Can go away once crtl is moved to rtl.h. */
#include "recog.h"
-#include "output.h"
-#include "basic-block.h"
-#include "cfglayout.h"
+#include "varasm.h"
+#include "rtl-error.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
#include "reload.h"
-#include "ggc.h"
-#include "timevar.h"
#include "tree-pass.h"
-#include "target.h"
-#include "df.h"
-#include "vecprim.h"
+#include "rtl-iter.h"
#ifdef STACK_REGS
Indexed by insn UIDs. A value of zero is uninitialized, one indicates
the insn uses stack registers, two indicates the insn does not use
stack registers. */
-static VEC(char,heap) *stack_regs_mentioned_data;
+static vec<char> stack_regs_mentioned_data;
#define REG_STACK_SIZE (LAST_STACK_REG - FIRST_STACK_REG + 1)
int top; /* index to top stack element */
HARD_REG_SET reg_set; /* set of live registers */
unsigned char reg[REG_STACK_SIZE];/* register - stack mapping */
-} *stack;
+} *stack_ptr;
/* This is used to carry information about basic blocks. It is
attached to the AUX field of the standard CFG block. */
/* Forward declarations */
static int stack_regs_mentioned_p (const_rtx pat);
-static void pop_stack (stack, int);
+static void pop_stack (stack_ptr, int);
static rtx *get_true_reg (rtx *);
-static int check_asm_stack_operands (rtx);
+static int check_asm_stack_operands (rtx_insn *);
static void get_asm_operands_in_out (rtx, int *, int *);
static rtx stack_result (tree);
static void replace_reg (rtx *, int);
-static void remove_regno_note (rtx, enum reg_note, unsigned int);
-static int get_hard_regnum (stack, rtx);
-static rtx emit_pop_insn (rtx, stack, rtx, enum emit_where);
-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 void remove_regno_note (rtx_insn *, enum reg_note, unsigned int);
+static int get_hard_regnum (stack_ptr, rtx);
+static rtx_insn *emit_pop_insn (rtx_insn *, stack_ptr, rtx, enum emit_where);
+static void swap_to_top (rtx_insn *, stack_ptr, rtx, rtx);
+static bool move_for_stack_reg (rtx_insn *, stack_ptr, rtx);
+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);
-static void compare_for_stack_reg (rtx, stack, rtx);
-static bool subst_stack_regs_pat (rtx, stack, rtx);
-static void subst_asm_stack_regs (rtx, stack);
-static bool subst_stack_regs (rtx, stack);
-static void change_stack (rtx, stack, stack, enum emit_where);
-static void print_stack (FILE *, stack);
-static rtx next_flags_user (rtx);
+static int swap_rtx_condition (rtx_insn *);
+static void compare_for_stack_reg (rtx_insn *, stack_ptr, rtx);
+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);
+static void change_stack (rtx_insn *, stack_ptr, stack_ptr, enum emit_where);
+static void print_stack (FILE *, stack_ptr);
+static rtx_insn *next_flags_user (rtx_insn *);
\f
/* Return nonzero if any stack register is mentioned somewhere within PAT. */
unsigned int uid, max;
int test;
- if (! INSN_P (insn) || !stack_regs_mentioned_data)
+ if (! INSN_P (insn) || !stack_regs_mentioned_data.exists ())
return 0;
uid = INSN_UID (insn);
- max = VEC_length (char, stack_regs_mentioned_data);
+ max = stack_regs_mentioned_data.length ();
if (uid >= max)
{
/* Allocate some extra size to avoid too many reallocs, but
do not grow too quickly. */
max = uid + uid / 20 + 1;
- VEC_safe_grow_cleared (char, heap, stack_regs_mentioned_data, max);
+ stack_regs_mentioned_data.safe_grow_cleared (max);
}
- test = VEC_index (char, stack_regs_mentioned_data, uid);
+ test = 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;
- VEC_replace (char, stack_regs_mentioned_data, uid, test);
+ stack_regs_mentioned_data[uid] = test;
}
return test == 1;
\f
static rtx ix86_flags_rtx;
-static rtx
-next_flags_user (rtx insn)
+static rtx_insn *
+next_flags_user (rtx_insn *insn)
{
/* Search forward looking for the first use of this value.
Stop at block boundaries. */
return insn;
if (CALL_P (insn))
- return NULL_RTX;
+ return NULL;
}
- return NULL_RTX;
+ return NULL;
}
\f
/* Reorganize the stack into ascending numbers, before this insn. */
static void
-straighten_stack (rtx insn, stack regstack)
+straighten_stack (rtx_insn *insn, stack_ptr regstack)
{
struct stack_def temp_stack;
int top;
/* Pop a register from the stack. */
static void
-pop_stack (stack regstack, int regno)
+pop_stack (stack_ptr regstack, int regno)
{
int top = regstack->top;
actual FP register in use. */
{
rtx subreg;
- if (FP_REG_P (subreg = SUBREG_REG (*pat)))
+ if (STACK_REG_P (subreg = SUBREG_REG (*pat)))
{
int regno_off = subreg_regno_offset (REGNO (subreg),
GET_MODE (subreg),
break;
case UNSPEC:
- if (XINT (*pat, 1) == UNSPEC_TRUNC_NOOP)
+ if (XINT (*pat, 1) == UNSPEC_TRUNC_NOOP
+ || XINT (*pat, 1) == UNSPEC_FILD_ATOMIC)
pat = & XVECEXP (*pat, 0, 0);
return pat;
numbers below refer to that explanation. */
static int
-check_asm_stack_operands (rtx insn)
+check_asm_stack_operands (rtx_insn *insn)
{
int i;
int n_clobbers;
char reg_used_as_output[FIRST_PSEUDO_REGISTER];
char implicitly_dies[FIRST_PSEUDO_REGISTER];
- int alt;
rtx *clobber_reg = 0;
int n_inputs, n_outputs;
/* Find out what the constraints require. If no constraint
alternative matches, this asm is malformed. */
- extract_insn (insn);
- constrain_operands (1);
- alt = which_alternative;
+ extract_constrain_insn (insn);
- preprocess_constraints ();
+ preprocess_constraints (insn);
get_asm_operands_in_out (body, &n_outputs, &n_inputs);
- if (alt < 0)
+ if (which_alternative < 0)
{
malformed_asm = 1;
/* Avoid further trouble with this insn. */
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
return 0;
}
+ const operand_alternative *op_alt = which_op_alt ();
/* Strip SUBREGs here to make the following code simpler. */
for (i = 0; i < recog_data.n_operands; i++)
for (i = 0; i < n_outputs; i++)
if (STACK_REG_P (recog_data.operand[i]))
{
- if (reg_class_size[(int) recog_op_alt[i][alt].cl] != 1)
+ if (reg_class_size[(int) op_alt[i].cl] != 1)
{
error_for_asm (insn, "output constraint %d must specify a single register", i);
malformed_asm = 1;
if (operands_match_p (clobber_reg[j], recog_data.operand[i]))
break;
- if (j < n_clobbers || recog_op_alt[i][alt].matches >= 0)
+ if (j < n_clobbers || op_alt[i].matches >= 0)
implicitly_dies[REGNO (recog_data.operand[i])] = 1;
}
record any earlyclobber. */
for (i = n_outputs; i < n_outputs + n_inputs; i++)
- if (recog_op_alt[i][alt].matches == -1)
+ if (op_alt[i].matches == -1)
{
int j;
number REGNO from INSN. Remove only one such note. */
static void
-remove_regno_note (rtx insn, enum reg_note note, unsigned int regno)
+remove_regno_note (rtx_insn *insn, enum reg_note note, unsigned int regno)
{
rtx *note_link, this_rtx;
returned if the register is not found. */
static int
-get_hard_regnum (stack regstack, rtx reg)
+get_hard_regnum (stack_ptr regstack, rtx reg)
{
int i;
and source is the top of stack. A death note for the top of stack
cases the movdf pattern to pop. */
-static rtx
-emit_pop_insn (rtx insn, stack regstack, rtx reg, enum emit_where where)
+static rtx_insn *
+emit_pop_insn (rtx_insn *insn, stack_ptr regstack, rtx reg, enum emit_where where)
{
- rtx pop_insn, pop_rtx;
+ rtx_insn *pop_insn;
+ rtx pop_rtx;
int hard_regno;
/* For complex types take care to pop both halves. These may survive in
rtx reg1 = FP_MODE_REG (REGNO (reg), DFmode);
rtx reg2 = FP_MODE_REG (REGNO (reg) + 1, DFmode);
- pop_insn = NULL_RTX;
+ pop_insn = NULL;
if (get_hard_regnum (regstack, reg1) >= 0)
pop_insn = emit_pop_insn (insn, regstack, reg1, where);
if (get_hard_regnum (regstack, reg2) >= 0)
gcc_assert (hard_regno >= FIRST_STACK_REG);
- pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode),
+ pop_rtx = gen_rtx_SET (FP_MODE_REG (hard_regno, DFmode),
FP_MODE_REG (FIRST_STACK_REG, DFmode));
if (where == EMIT_AFTER)
If REG is already at the top of the stack, no insn is emitted. */
static void
-emit_swap_insn (rtx insn, stack regstack, rtx reg)
+emit_swap_insn (rtx_insn *insn, stack_ptr regstack, rtx reg)
{
int hard_regno;
rtx swap_rtx;
- int tmp, other_reg; /* swap regno temps */
- rtx i1; /* the stack-reg insn prior to INSN */
+ 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 */
hard_regno = get_hard_regnum (regstack, reg);
gcc_assert (hard_regno >= FIRST_STACK_REG);
other_reg = regstack->top - (hard_regno - FIRST_STACK_REG);
-
- tmp = regstack->reg[other_reg];
- regstack->reg[other_reg] = regstack->reg[regstack->top];
- regstack->reg[regstack->top] = tmp;
+ std::swap (regstack->reg[regstack->top], regstack->reg[other_reg]);
/* Find the previous insn involving stack regs, but don't pass a
block boundary. */
i1 = NULL;
if (current_block && insn != BB_HEAD (current_block))
{
- rtx tmp = PREV_INSN (insn);
- rtx limit = PREV_INSN (BB_HEAD (current_block));
+ rtx_insn *tmp = PREV_INSN (insn);
+ rtx_insn *limit = PREV_INSN (BB_HEAD (current_block));
while (tmp != limit)
{
if (LABEL_P (tmp)
is emitted. */
static void
-swap_to_top (rtx insn, stack regstack, rtx src1, rtx src2)
+swap_to_top (rtx_insn *insn, stack_ptr regstack, rtx src1, rtx src2)
{
struct stack_def temp_stack;
- int regno, j, k, temp;
+ int regno, j, k;
temp_stack = *regstack;
k = temp_stack.top - (regno - FIRST_STACK_REG);
j = temp_stack.top;
- temp = temp_stack.reg[k];
- temp_stack.reg[k] = temp_stack.reg[j];
- temp_stack.reg[j] = temp;
+ std::swap (temp_stack.reg[j], temp_stack.reg[k]);
}
/* Place operand 2 next on the stack. */
k = temp_stack.top - (regno - FIRST_STACK_REG);
j = temp_stack.top - 1;
- temp = temp_stack.reg[k];
- temp_stack.reg[k] = temp_stack.reg[j];
- temp_stack.reg[j] = temp;
+ std::swap (temp_stack.reg[j], temp_stack.reg[k]);
}
change_stack (insn, regstack, &temp_stack, EMIT_BEFORE);
was deleted in the process. */
static bool
-move_for_stack_reg (rtx insn, stack regstack, rtx pat)
+move_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx pat)
{
rtx *psrc = get_true_reg (&SET_SRC (pat));
rtx *pdest = get_true_reg (&SET_DEST (pat));
a NaN into DEST, then invokes move_for_stack_reg. */
static bool
-move_nan_for_stack_reg (rtx insn, stack regstack, rtx dest)
+move_nan_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx dest)
{
rtx pat;
dest = FP_MODE_REG (REGNO (dest), SFmode);
- pat = gen_rtx_SET (VOIDmode, dest, not_a_num);
+ pat = gen_rtx_SET (dest, not_a_num);
PATTERN (insn) = pat;
INSN_CODE (insn) = -1;
}
static int
-swap_rtx_condition (rtx insn)
+swap_rtx_condition (rtx_insn *insn)
{
rtx pat = PATTERN (insn);
set up. */
static void
-compare_for_stack_reg (rtx insn, stack regstack, rtx pat_src)
+compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx pat_src)
{
rtx *src1, *src2;
rtx src1_note, src2_note;
&& get_hard_regnum (regstack, *src2) == FIRST_STACK_REG))
&& swap_rtx_condition (insn))
{
- rtx temp;
- temp = XEXP (pat_src, 0);
- XEXP (pat_src, 0) = XEXP (pat_src, 1);
- XEXP (pat_src, 1) = temp;
+ std::swap (XEXP (pat_src, 0), XEXP (pat_src, 1));
src1 = get_true_reg (&XEXP (pat_src, 0));
src2 = get_true_reg (&XEXP (pat_src, 1));
/* 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); */
-
remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0)));
-
emit_pop_insn (insn, regstack, XEXP (src2_note, 0),
EMIT_AFTER);
}
}
}
\f
-/* Substitute new registers in LOC, which is part of a debug insn.
- REGSTACK is the current register layout. */
+/* Substitute hardware stack regs in debug insn INSN, using stack
+ layout REGSTACK. If we can't find a hardware stack reg for any of
+ the REGs in it, reset the debug insn. */
-static int
-subst_stack_regs_in_debug_insn (rtx *loc, void *data)
+static void
+subst_all_stack_regs_in_debug_insn (rtx_insn *insn, struct stack_def *regstack)
{
- rtx *tloc = get_true_reg (loc);
- stack regstack = (stack)data;
- int hard_regno;
-
- if (!STACK_REG_P (*tloc))
- return 0;
-
- if (tloc != loc)
- return 0;
-
- hard_regno = get_hard_regnum (regstack, *loc);
- gcc_assert (hard_regno >= FIRST_STACK_REG);
+ subrtx_ptr_iterator::array_type array;
+ FOR_EACH_SUBRTX_PTR (iter, array, &INSN_VAR_LOCATION_LOC (insn), NONCONST)
+ {
+ rtx *loc = *iter;
+ rtx x = *loc;
+ if (STACK_REG_P (x))
+ {
+ int hard_regno = get_hard_regnum (regstack, x);
- replace_reg (loc, hard_regno);
+ /* If we can't find an active register, reset this debug insn. */
+ if (hard_regno == -1)
+ {
+ INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
+ return;
+ }
- return -1;
+ gcc_assert (hard_regno >= FIRST_STACK_REG);
+ replace_reg (loc, hard_regno);
+ iter.skip_subrtxes ();
+ }
+ }
}
/* Substitute new registers in PAT, which is part of INSN. REGSTACK
was deleted in the process. */
static bool
-subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
+subst_stack_regs_pat (rtx_insn *insn, stack_ptr regstack, rtx pat)
{
rtx *dest, *src;
bool control_flow_insn_deleted = false;
if (get_hard_regnum (regstack, u) == -1)
{
rtx pat2 = gen_rtx_CLOBBER (VOIDmode, u);
- rtx insn2 = emit_insn_before (pat2, insn);
+ rtx_insn *insn2 = emit_insn_before (pat2, insn);
control_flow_insn_deleted
|= move_nan_for_stack_reg (insn2, regstack, u);
}
if (STACK_REG_P (*src)
|| (STACK_REG_P (*dest)
&& (REG_P (*src) || MEM_P (*src)
- || GET_CODE (*src) == CONST_DOUBLE)))
+ || CONST_DOUBLE_P (*src))))
{
control_flow_insn_deleted |= move_for_stack_reg (insn, regstack, pat);
break;
case CALL:
{
int count;
- for (count = hard_regno_nregs[REGNO (*dest)][GET_MODE (*dest)];
- --count >= 0;)
+ for (count = REG_NREGS (*dest); --count >= 0;)
{
regstack->reg[++regstack->top] = REGNO (*dest) + count;
SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest) + count);
if (src1_hard_regnum == -1)
{
rtx pat2 = gen_rtx_CLOBBER (VOIDmode, *src1);
- rtx insn2 = emit_insn_before (pat2, insn);
+ rtx_insn *insn2 = emit_insn_before (pat2, insn);
control_flow_insn_deleted
|= move_nan_for_stack_reg (insn2, regstack, *src1);
}
if (src2_hard_regnum == -1)
{
rtx pat2 = gen_rtx_CLOBBER (VOIDmode, *src2);
- rtx insn2 = emit_insn_before (pat2, insn);
+ rtx_insn *insn2 = emit_insn_before (pat2, insn);
control_flow_insn_deleted
|= move_nan_for_stack_reg (insn2, regstack, *src2);
}
switch (XINT (pat_src, 1))
{
case UNSPEC_FIST:
+ case UNSPEC_FIST_ATOMIC:
case UNSPEC_FIST_FLOOR:
case UNSPEC_FIST_CEIL:
requirements, since record_asm_stack_regs removes any problem asm. */
static void
-subst_asm_stack_regs (rtx insn, stack regstack)
+subst_asm_stack_regs (rtx_insn *insn, stack_ptr regstack)
{
rtx body = PATTERN (insn);
- int alt;
rtx *note_reg; /* Array of note contents */
rtx **note_loc; /* Address of REG field of each note */
/* Find out what the constraints required. If no constraint
alternative matches, that is a compiler bug: we should have caught
such an insn in check_asm_stack_operands. */
- extract_insn (insn);
- constrain_operands (1);
- alt = which_alternative;
+ extract_constrain_insn (insn);
- preprocess_constraints ();
+ preprocess_constraints (insn);
+ const operand_alternative *op_alt = which_op_alt ();
get_asm_operands_in_out (body, &n_outputs, &n_inputs);
- gcc_assert (alt >= 0);
-
/* Strip SUBREGs here to make the following code simpler. */
for (i = 0; i < recog_data.n_operands; i++)
if (GET_CODE (recog_data.operand[i]) == SUBREG
n_notes = 0;
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
{
+ if (GET_CODE (note) != EXPR_LIST)
+ continue;
rtx reg = XEXP (note, 0);
rtx *loc = & XEXP (note, 0);
for (i = n_outputs; i < n_outputs + n_inputs; i++)
if (STACK_REG_P (recog_data.operand[i])
- && reg_class_subset_p (recog_op_alt[i][alt].cl,
- FLOAT_REGS)
- && recog_op_alt[i][alt].cl != FLOAT_REGS)
+ && reg_class_subset_p (op_alt[i].cl, FLOAT_REGS)
+ && op_alt[i].cl != FLOAT_REGS)
{
/* If an operand needs to be in a particular reg in
FLOAT_REGS, the constraint was either 't' or 'u'. Since
it and swap it with whatever is already in I's place.
K is where recog_data.operand[i] is now. J is where it
should be. */
- int j, k, temp;
+ int j, k;
k = temp_stack.top - (regno - FIRST_STACK_REG);
j = (temp_stack.top
- (REGNO (recog_data.operand[i]) - FIRST_STACK_REG));
- temp = temp_stack.reg[k];
- temp_stack.reg[k] = temp_stack.reg[j];
- temp_stack.reg[j] = temp;
+ std::swap (temp_stack.reg[j], temp_stack.reg[k]);
}
}
if (operands_match_p (clobber_reg[j], recog_data.operand[i]))
break;
- if (j < n_clobbers || recog_op_alt[i][alt].matches >= 0)
+ if (j < n_clobbers || op_alt[i].matches >= 0)
{
/* recog_data.operand[i] might not be at the top of stack.
But that's OK, because all we need to do is pop the
a control flow insn was deleted in the process. */
static bool
-subst_stack_regs (rtx insn, stack regstack)
+subst_stack_regs (rtx_insn *insn, stack_ptr regstack)
{
rtx *note_link, note;
bool control_flow_insn_deleted = false;
/* subst_stack_regs_pat may have deleted a no-op insn. If so, any
REG_UNUSED will already have been dealt with, so just return. */
- if (NOTE_P (insn) || INSN_DELETED_P (insn))
+ if (NOTE_P (insn) || insn->deleted ())
return control_flow_insn_deleted;
/* If this a noreturn call, we can't insert pop insns after it.
is no longer needed once this has executed. */
static void
-change_stack (rtx insn, stack old, stack new_stack, enum emit_where where)
+change_stack (rtx_insn *insn, stack_ptr old, stack_ptr new_stack,
+ enum emit_where where)
{
int reg;
int update_end = 0;
{
old->reg[++old->top] = i;
SET_HARD_REG_BIT (old->reg_set, i);
- emit_insn_before (gen_rtx_SET (VOIDmode,
- FP_MODE_REG (i, SFmode), not_a_num), insn);
+ emit_insn_before (gen_rtx_SET (FP_MODE_REG (i, SFmode), not_a_num),
+ insn);
}
/* Pop any registers that are not needed in the new block. */
/* 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. */
+ to pop registers that minimizes the number of fxchs below. */
if (new_stack->top > 0)
{
bool slots[REG_STACK_SIZE];
/* Print stack configuration. */
static void
-print_stack (FILE *file, stack s)
+print_stack (FILE *file, stack_ptr s)
{
if (! file)
return;
Note that we are inserting converted code here. This code is
never seen by the convert_regs pass. */
- FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
+ FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)
{
basic_block block = e->dest;
block_info bi = BLOCK_INFO (block);
bi->stack_in.reg[++top] = reg;
- init = gen_rtx_SET (VOIDmode,
- FP_MODE_REG (FIRST_STACK_REG, SFmode),
+ init = gen_rtx_SET (FP_MODE_REG (FIRST_STACK_REG, SFmode),
not_a_num);
insert_insn_on_edge (init, e);
inserted = 1;
convert_regs_exit (void)
{
int value_reg_low, value_reg_high;
- stack output_stack;
+ stack_ptr output_stack;
rtx retvalue;
retvalue = stack_result (current_function_decl);
if (retvalue)
{
value_reg_low = REGNO (retvalue);
- value_reg_high = END_HARD_REGNO (retvalue) - 1;
+ value_reg_high = END_REGNO (retvalue) - 1;
}
- output_stack = &BLOCK_INFO (EXIT_BLOCK_PTR)->stack_in;
+ output_stack = &BLOCK_INFO (EXIT_BLOCK_PTR_FOR_FN (cfun))->stack_in;
if (value_reg_low == -1)
output_stack->top = -1;
else
static void
propagate_stack (edge e)
{
- stack src_stack = &BLOCK_INFO (e->src)->stack_out;
- stack dest_stack = &BLOCK_INFO (e->dest)->stack_in;
+ stack_ptr src_stack = &BLOCK_INFO (e->src)->stack_out;
+ stack_ptr dest_stack = &BLOCK_INFO (e->dest)->stack_in;
int reg;
/* Preserve the order of the original stack, but check whether
compensate_edge (edge e)
{
basic_block source = e->src, target = e->dest;
- stack target_stack = &BLOCK_INFO (target)->stack_in;
- stack source_stack = &BLOCK_INFO (source)->stack_out;
+ stack_ptr target_stack = &BLOCK_INFO (target)->stack_in;
+ stack_ptr source_stack = &BLOCK_INFO (source)->stack_out;
struct stack_def regstack;
int reg;
}
else
{
- rtx seq, after;
+ rtx_insn *seq;
+ rtx_note *after;
current_block = NULL;
start_sequence ();
starting_stack_p = false;
- FOR_EACH_BB (bb)
- if (bb != ENTRY_BLOCK_PTR)
+ FOR_EACH_BB_FN (bb, cfun)
+ if (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun))
{
edge e;
edge_iterator ei;
return (e1->src->index < e2->src->index) ? e1 : e2;
}
-/* Convert stack register references in one block. */
+/* Convert stack register references in one block. Return true if the CFG
+ has been modified in the process. */
-static void
+static bool
convert_regs_1 (basic_block block)
{
struct stack_def regstack;
block_info bi = BLOCK_INFO (block);
int reg;
- rtx insn, next;
+ rtx_insn *insn, *next;
bool control_flow_insn_deleted = false;
+ bool cfg_altered = false;
int debug_insns_with_starting_stack = 0;
any_malformed_asm = false;
debug_insns_with_starting_stack++;
else
{
- for_each_rtx (&PATTERN (insn), subst_stack_regs_in_debug_insn,
- ®stack);
+ subst_all_stack_regs_in_debug_insn (insn, ®stack);
/* Nothing must ever die at a debug insn. If something
is referenced in it that becomes dead, it should have
continue;
debug_insns_with_starting_stack--;
- for_each_rtx (&PATTERN (insn), subst_stack_regs_in_debug_insn,
- &bi->stack_in);
+ subst_all_stack_regs_in_debug_insn (insn, &bi->stack_in);
}
}
if (dump_file)
fprintf (dump_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 (FP_MODE_REG (reg, SFmode), not_a_num);
insn = emit_insn_after (set, insn);
control_flow_insn_deleted |= subst_stack_regs (insn, ®stack);
}
place, still, but we don't have enough information at that time. */
if (control_flow_insn_deleted)
- purge_dead_edges (block);
+ cfg_altered |= purge_dead_edges (block);
/* Something failed if the stack lives don't match. If we had malformed
asms, we zapped the instruction itself, but that didn't produce the
|| any_malformed_asm);
bi->stack_out = regstack;
bi->done = true;
+
+ return cfg_altered;
}
-/* Convert registers in all blocks reachable from BLOCK. */
+/* Convert registers in all blocks reachable from BLOCK. Return true if the
+ CFG has been modified in the process. */
-static void
+static bool
convert_regs_2 (basic_block block)
{
basic_block *stack, *sp;
+ bool cfg_altered = false;
/* We process the blocks in a top-down manner, in a way such that one block
is only processed after all its predecessors. The number of predecessors
of every block has already been computed. */
- stack = XNEWVEC (basic_block, n_basic_blocks);
+ stack = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun));
sp = stack;
*sp++ = block;
*sp++ = e->dest;
}
- convert_regs_1 (block);
+ cfg_altered |= convert_regs_1 (block);
}
while (sp != stack);
free (stack);
+
+ return cfg_altered;
}
/* Traverse all basic blocks in a function, converting the register
static void
convert_regs (void)
{
+ bool cfg_altered = false;
int inserted;
basic_block b;
edge e;
/* Construct the desired stack for function exit. */
convert_regs_exit ();
- BLOCK_INFO (EXIT_BLOCK_PTR)->done = 1;
+ BLOCK_INFO (EXIT_BLOCK_PTR_FOR_FN (cfun))->done = 1;
/* ??? Future: process inner loops first, and give them arbitrary
initial stacks which emit_swap_insn can modify. This ought to
prevent double fxch that often appears at the head of a loop. */
/* Process all blocks reachable from all entry points. */
- FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
- convert_regs_2 (e->dest);
+ FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)
+ cfg_altered |= convert_regs_2 (e->dest);
/* ??? Process all unreachable blocks. Though there's no excuse
for keeping these even when not optimizing. */
- FOR_EACH_BB (b)
+ FOR_EACH_BB_FN (b, cfun)
{
block_info bi = BLOCK_INFO (b);
if (! bi->done)
- convert_regs_2 (b);
+ cfg_altered |= convert_regs_2 (b);
}
+ /* We must fix up abnormal edges before inserting compensation code
+ because both mechanisms insert insns on edges. */
+ inserted |= fixup_abnormal_edges ();
+
inserted |= compensate_edges ();
clear_aux_for_blocks ();
- fixup_abnormal_edges ();
if (inserted)
commit_edge_insertions ();
+ if (cfg_altered)
+ cleanup_cfg (0);
+
if (dump_file)
fputc ('\n', dump_file);
}
int max_uid;
/* Clean up previous run. */
- if (stack_regs_mentioned_data != NULL)
- VEC_free (char, heap, stack_regs_mentioned_data);
+ stack_regs_mentioned_data.release ();
/* See if there is something to do. Flow analysis is quite
expensive so we might save some compilation time. */
/* Set up block info for each basic block. */
alloc_aux_for_blocks (sizeof (struct block_info_def));
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
block_info bi = BLOCK_INFO (bb);
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->preds)
if (!(e->flags & EDGE_DFS_BACK)
- && e->src != ENTRY_BLOCK_PTR)
+ && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
bi->predecessors++;
/* Set current register status at last instruction `uninitialized'. */
/* Create the replacement registers up front. */
for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
{
- enum machine_mode mode;
+ machine_mode mode;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
REAL_VALUE_TYPE r;
real_nan (&r, "", 1, SFmode);
- not_a_num = CONST_DOUBLE_FROM_REAL_VALUE (r, SFmode);
+ not_a_num = const_double_from_real_value (r, SFmode);
not_a_num = force_const_mem (SFmode, not_a_num);
}
/* Allocate a cache for stack_regs_mentioned. */
max_uid = get_max_uid ();
- stack_regs_mentioned_data = VEC_alloc (char, heap, max_uid + 1);
- memset (VEC_address (char, stack_regs_mentioned_data),
+ stack_regs_mentioned_data.create (max_uid + 1);
+ memset (stack_regs_mentioned_data.address (),
0, sizeof (char) * (max_uid + 1));
convert_regs ();
}
#endif /* STACK_REGS */
\f
-static bool
-gate_handle_stack_regs (void)
+namespace {
+
+const pass_data pass_data_stack_regs =
+{
+ RTL_PASS, /* type */
+ "*stack_regs", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_REG_STACK, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_stack_regs : public rtl_opt_pass
{
+public:
+ pass_stack_regs (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_stack_regs, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
#ifdef STACK_REGS
- return 1;
+ return true;
#else
- return 0;
+ return false;
#endif
-}
+ }
+
+}; // class pass_stack_regs
-struct rtl_opt_pass pass_stack_regs =
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_stack_regs (gcc::context *ctxt)
{
- {
- RTL_PASS,
- "*stack_regs", /* name */
- gate_handle_stack_regs, /* gate */
- NULL, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_REG_STACK, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
-};
+ return new pass_stack_regs (ctxt);
+}
/* Convert register usage from flat register file usage to a stack
register file. */
return 0;
}
-struct rtl_opt_pass pass_stack_regs_run =
+namespace {
+
+const pass_data pass_data_stack_regs_run =
{
- {
- RTL_PASS,
- "stack", /* name */
- NULL, /* gate */
- rest_of_handle_stack_regs, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_REG_STACK, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_df_finish | TODO_verify_rtl_sharing |
- TODO_dump_func |
- TODO_ggc_collect /* todo_flags_finish */
- }
+ RTL_PASS, /* type */
+ "stack", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_REG_STACK, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_df_finish, /* todo_flags_finish */
};
+
+class pass_stack_regs_run : public rtl_opt_pass
+{
+public:
+ pass_stack_regs_run (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_stack_regs_run, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual unsigned int execute (function *)
+ {
+ return rest_of_handle_stack_regs ();
+ }
+
+}; // class pass_stack_regs_run
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_stack_regs_run (gcc::context *ctxt)
+{
+ return new pass_stack_regs_run (ctxt);
+}