#include "tm_p.h"
#include "insn-config.h"
#include "regs.h"
+#include "addresses.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "reload.h"
terminate_write,
terminate_dead,
mark_read,
- mark_write
+ mark_write,
+ /* mark_access is for marking the destination regs in
+ REG_FRAME_RELATED_EXPR notes (as if they were read) so that the
+ note is updated properly. */
+ mark_access
};
static const char * const scan_actions_name[] =
"terminate_write",
"terminate_dead",
"mark_read",
- "mark_write"
+ "mark_write",
+ "mark_access"
};
static struct obstack rename_obstack;
/* Perform register renaming on the current function. */
-void
+static void
regrename_optimize (void)
{
int tick[FIRST_PSEUDO_REGISTER];
return;
}
- if ((type == OP_OUT && action != terminate_write)
- || (type != OP_OUT && action == terminate_write))
+ if ((type == OP_OUT) != (action == terminate_write || action == mark_access))
return;
for (p = &open_chains; *p;)
continue;
}
- if (action == mark_read)
+ if (action == mark_read || action == mark_access)
{
gcc_assert (exact_match);
const char *fmt;
int i, j;
- if (action == mark_write)
+ if (action == mark_write || action == mark_access)
return;
switch (code)
rtx op1 = orig_op1;
rtx *locI = NULL;
rtx *locB = NULL;
- rtx *locB_reg = NULL;
+ enum rtx_code index_code = SCRATCH;
if (GET_CODE (op0) == SUBREG)
{
{
locI = &XEXP (x, 0);
locB = &XEXP (x, 1);
+ index_code = GET_CODE (*locI);
}
else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE
|| code1 == ZERO_EXTEND || code0 == MEM)
{
locI = &XEXP (x, 1);
locB = &XEXP (x, 0);
+ index_code = GET_CODE (*locI);
}
else if (code0 == CONST_INT || code0 == CONST
|| code0 == SYMBOL_REF || code0 == LABEL_REF)
- locB = &XEXP (x, 1);
+ {
+ locB = &XEXP (x, 1);
+ index_code = GET_CODE (XEXP (x, 0));
+ }
else if (code1 == CONST_INT || code1 == CONST
|| code1 == SYMBOL_REF || code1 == LABEL_REF)
- locB = &XEXP (x, 0);
+ {
+ locB = &XEXP (x, 0);
+ index_code = GET_CODE (XEXP (x, 1));
+ }
else if (code0 == REG && code1 == REG)
{
int index_op;
+ unsigned regno0 = REGNO (op0), regno1 = REGNO (op1);
- if (REG_OK_FOR_INDEX_P (op0)
- && REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
+ if (REGNO_OK_FOR_INDEX_P (regno0)
+ && regno_ok_for_base_p (regno1, mode, PLUS, REG))
index_op = 0;
- else if (REG_OK_FOR_INDEX_P (op1)
- && REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
+ else if (REGNO_OK_FOR_INDEX_P (regno1)
+ && regno_ok_for_base_p (regno0, mode, PLUS, REG))
index_op = 1;
- else if (REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
+ else if (regno_ok_for_base_p (regno1, mode, PLUS, REG))
index_op = 0;
- else if (REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
+ else if (regno_ok_for_base_p (regno0, mode, PLUS, REG))
index_op = 1;
- else if (REG_OK_FOR_INDEX_P (op1))
+ else if (REGNO_OK_FOR_INDEX_P (regno1))
index_op = 1;
else
index_op = 0;
locI = &XEXP (x, index_op);
- locB_reg = &XEXP (x, !index_op);
+ locB = &XEXP (x, !index_op);
+ index_code = GET_CODE (*locI);
}
else if (code0 == REG)
{
locI = &XEXP (x, 0);
locB = &XEXP (x, 1);
+ index_code = GET_CODE (*locI);
}
else if (code1 == REG)
{
locI = &XEXP (x, 1);
locB = &XEXP (x, 0);
+ index_code = GET_CODE (*locI);
}
if (locI)
scan_rtx_address (insn, locI, INDEX_REG_CLASS, action, mode);
if (locB)
- scan_rtx_address (insn, locB, MODE_BASE_REG_CLASS (mode), action, mode);
- if (locB_reg)
- scan_rtx_address (insn, locB_reg, MODE_BASE_REG_REG_CLASS (mode),
+ scan_rtx_address (insn, locB, base_reg_class (mode, PLUS, index_code),
action, mode);
+
return;
}
case MEM:
scan_rtx_address (insn, &XEXP (x, 0),
- MODE_BASE_REG_CLASS (GET_MODE (x)), action,
+ base_reg_class (GET_MODE (x), MEM, SCRATCH), action,
GET_MODE (x));
return;
case MEM:
scan_rtx_address (insn, &XEXP (x, 0),
- MODE_BASE_REG_CLASS (GET_MODE (x)), action,
+ base_reg_class (GET_MODE (x), MEM, SCRATCH), action,
GET_MODE (x));
return;
scan_rtx (insn, loc, cl, mark_read, type, 0);
}
- /* Step 4: Close chains for registers that die here.
- Also record updates for REG_INC notes. */
+ /* Step 3B: Record updates for regs in REG_INC notes, and
+ source regs in REG_FRAME_RELATED_EXPR notes. */
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- {
- if (REG_NOTE_KIND (note) == REG_DEAD)
- scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead,
- OP_IN, 0);
- else if (REG_NOTE_KIND (note) == REG_INC)
- scan_rtx (insn, &XEXP (note, 0), ALL_REGS, mark_read,
- OP_INOUT, 0);
- }
+ if (REG_NOTE_KIND (note) == REG_INC
+ || REG_NOTE_KIND (note) == REG_FRAME_RELATED_EXPR)
+ scan_rtx (insn, &XEXP (note, 0), ALL_REGS, mark_read,
+ OP_INOUT, 0);
+
+ /* Step 4: Close chains for registers that die here. */
+ for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_DEAD)
+ scan_rtx (insn, &XEXP (note, 0), NO_REGS, terminate_dead,
+ OP_IN, 0);
/* Step 4B: If this is a call, any chain live at this point
requires a caller-saved reg. */
recog_op_alt[opn][alt].earlyclobber);
}
+ /* Step 6B: Record destination regs in REG_FRAME_RELATED_EXPR
+ notes for update. */
+ for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_FRAME_RELATED_EXPR)
+ scan_rtx (insn, &XEXP (note, 0), ALL_REGS, mark_access,
+ OP_INOUT, 0);
+
/* Step 7: Close chains for registers that were never
really used here. */
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
fprintf (dump_file, "insn %u: replaced reg %u with %u\n",
INSN_UID (insn), REGNO (*loc), REGNO (new));
- *loc = new;
+ validate_change (insn, loc, new, 1);
return true;
}
return false;
rtx op1 = orig_op1;
rtx *locI = NULL;
rtx *locB = NULL;
- rtx *locB_reg = NULL;
+ enum rtx_code index_code = SCRATCH;
if (GET_CODE (op0) == SUBREG)
{
{
locI = &XEXP (x, 0);
locB = &XEXP (x, 1);
+ index_code = GET_CODE (*locI);
}
else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE
|| code1 == ZERO_EXTEND || code0 == MEM)
{
locI = &XEXP (x, 1);
locB = &XEXP (x, 0);
+ index_code = GET_CODE (*locI);
}
else if (code0 == CONST_INT || code0 == CONST
|| code0 == SYMBOL_REF || code0 == LABEL_REF)
- locB = &XEXP (x, 1);
+ {
+ locB = &XEXP (x, 1);
+ index_code = GET_CODE (XEXP (x, 0));
+ }
else if (code1 == CONST_INT || code1 == CONST
|| code1 == SYMBOL_REF || code1 == LABEL_REF)
- locB = &XEXP (x, 0);
+ {
+ locB = &XEXP (x, 0);
+ index_code = GET_CODE (XEXP (x, 1));
+ }
else if (code0 == REG && code1 == REG)
{
int index_op;
+ unsigned regno0 = REGNO (op0), regno1 = REGNO (op1);
- if (REG_OK_FOR_INDEX_P (op0)
- && REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
+ if (REGNO_OK_FOR_INDEX_P (regno0)
+ && regno_ok_for_base_p (regno1, mode, PLUS, REG))
index_op = 0;
- else if (REG_OK_FOR_INDEX_P (op1)
- && REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
+ else if (REGNO_OK_FOR_INDEX_P (regno1)
+ && regno_ok_for_base_p (regno0, mode, PLUS, REG))
index_op = 1;
- else if (REG_MODE_OK_FOR_REG_BASE_P (op1, mode))
+ else if (regno_ok_for_base_p (regno1, mode, PLUS, REG))
index_op = 0;
- else if (REG_MODE_OK_FOR_REG_BASE_P (op0, mode))
+ else if (regno_ok_for_base_p (regno0, mode, PLUS, REG))
index_op = 1;
- else if (REG_OK_FOR_INDEX_P (op1))
+ else if (REGNO_OK_FOR_INDEX_P (regno1))
index_op = 1;
else
index_op = 0;
locI = &XEXP (x, index_op);
- locB_reg = &XEXP (x, !index_op);
+ locB = &XEXP (x, !index_op);
+ index_code = GET_CODE (*locI);
}
else if (code0 == REG)
{
locI = &XEXP (x, 0);
locB = &XEXP (x, 1);
+ index_code = GET_CODE (*locI);
}
else if (code1 == REG)
{
locI = &XEXP (x, 1);
locB = &XEXP (x, 0);
+ index_code = GET_CODE (*locI);
}
if (locI)
insn, vd);
if (locB)
changed |= replace_oldest_value_addr (locB,
- MODE_BASE_REG_CLASS (mode),
- mode, insn, vd);
- if (locB_reg)
- changed |= replace_oldest_value_addr (locB_reg,
- MODE_BASE_REG_REG_CLASS (mode),
+ base_reg_class (mode, PLUS,
+ index_code),
mode, insn, vd);
return changed;
}
replace_oldest_value_mem (rtx x, rtx insn, struct value_data *vd)
{
return replace_oldest_value_addr (&XEXP (x, 0),
- MODE_BASE_REG_CLASS (GET_MODE (x)),
+ base_reg_class (GET_MODE (x), MEM,
+ SCRATCH),
GET_MODE (x), insn, vd);
}
for (insn = BB_HEAD (bb); ; insn = NEXT_INSN (insn))
{
int n_ops, i, alt, predicated;
- bool is_asm;
+ bool is_asm, any_replacements;
rtx set;
+ bool replaced[MAX_RECOG_OPERANDS];
if (! INSN_P (insn))
{
}
no_move_special_case:
+ any_replacements = false;
+
/* For each input operand, replace a hard register with the
eldest live copy that's in an appropriate register class. */
for (i = 0; i < n_ops; i++)
{
- bool replaced = false;
+ replaced[i] = false;
/* Don't scan match_operand here, since we've no reg class
information to pass down. Any operands that we could
if (recog_data.operand_type[i] == OP_IN)
{
if (recog_op_alt[i][alt].is_address)
- replaced
+ replaced[i]
= replace_oldest_value_addr (recog_data.operand_loc[i],
recog_op_alt[i][alt].cl,
VOIDmode, insn, vd);
else if (REG_P (recog_data.operand[i]))
- replaced
+ replaced[i]
= replace_oldest_value_reg (recog_data.operand_loc[i],
recog_op_alt[i][alt].cl,
insn, vd);
else if (MEM_P (recog_data.operand[i]))
- replaced = replace_oldest_value_mem (recog_data.operand[i],
- insn, vd);
+ replaced[i] = replace_oldest_value_mem (recog_data.operand[i],
+ insn, vd);
}
else if (MEM_P (recog_data.operand[i]))
- replaced = replace_oldest_value_mem (recog_data.operand[i],
- insn, vd);
+ replaced[i] = replace_oldest_value_mem (recog_data.operand[i],
+ insn, vd);
/* If we performed any replacement, update match_dups. */
- if (replaced)
+ if (replaced[i])
{
int j;
rtx new;
- changed = true;
-
new = *recog_data.operand_loc[i];
recog_data.operand[i] = new;
for (j = 0; j < recog_data.n_dups; j++)
if (recog_data.dup_num[j] == i)
- *recog_data.dup_loc[j] = new;
+ validate_change (insn, recog_data.dup_loc[j], new, 1);
+
+ any_replacements = true;
}
}
+ if (any_replacements)
+ {
+ if (! apply_change_group ())
+ {
+ for (i = 0; i < n_ops; i++)
+ if (replaced[i])
+ {
+ rtx old = *recog_data.operand_loc[i];
+ recog_data.operand[i] = old;
+ }
+
+ if (dump_file)
+ fprintf (dump_file,
+ "insn %u: reg replacements not verified\n",
+ INSN_UID (insn));
+ }
+ else
+ changed = true;
+ }
+
did_replacement:
/* Clobber call-clobbered registers. */
if (CALL_P (insn))
/* Main entry point for the forward copy propagation optimization. */
-void
+static void
copyprop_hardreg_forward (void)
{
struct value_data *all_vd;
need_refresh = false;
- all_vd = xmalloc (sizeof (struct value_data) * last_basic_block);
+ all_vd = XNEWVEC (struct value_data, last_basic_block);
- visited = sbitmap_alloc (last_basic_block - (INVALID_BLOCK + 1));
+ visited = sbitmap_alloc (last_basic_block);
sbitmap_zero (visited);
FOR_EACH_BB (bb)
{
- SET_BIT (visited, bb->index - (INVALID_BLOCK + 1));
+ SET_BIT (visited, bb->index);
/* If a block has a single predecessor, that we've already
processed, begin with the value data that was live at
the end of the predecessor block. */
/* ??? Ought to use more intelligent queuing of blocks. */
- if (single_pred_p (bb)
- && TEST_BIT (visited,
- single_pred (bb)->index - (INVALID_BLOCK + 1))
+ if (single_pred_p (bb)
+ && TEST_BIT (visited, single_pred (bb)->index)
&& ! (single_pred_edge (bb)->flags & (EDGE_ABNORMAL_CALL | EDGE_EH)))
all_vd[bb->index] = all_vd[single_pred (bb)->index];
else
/* Run the regrename and cprop passes. */
-static void
+static unsigned int
rest_of_handle_regrename (void)
{
if (flag_rename_registers)
regrename_optimize ();
if (flag_cprop_registers)
copyprop_hardreg_forward ();
+ return 0;
}
struct tree_opt_pass pass_regrename =