#include "recog.h"
#include "bitmap.h"
#include "expr.h"
+#include "except.h"
#include "regs.h"
#include "tree-pass.h"
+#include "df.h"
#ifdef STACK_GROWS_DOWNWARD
# undef STACK_GROWS_DOWNWARD
if (GET_CODE (x) == LABEL_REF
|| GET_CODE (x) == SYMBOL_REF
- || GET_CODE (x) == HIGH)
+ || GET_CODE (x) == HIGH
+ || GET_CODE (x) == CONST)
return false;
if (MEM_P (x)
== BLKmode))
return NULL_RTX;
+ /* Reject PARTIAL_INT modes. They are used for processor specific
+ purposes and it's probably best not to tamper with them. */
+ if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+ return NULL_RTX;
+
return set;
}
bitmap_set_bit (decomposable_context, regno);
return -1;
}
+
+ /* If this is a cast from one mode to another, where the modes
+ have the same size, and they are not tieable, then mark this
+ register as non-decomposable. If we decompose it we are
+ likely to mess up whatever the backend is trying to do. */
+ if (outer_words > 1
+ && outer_size == inner_size
+ && !MODES_TIEABLE_P (GET_MODE (x), GET_MODE (inner)))
+ {
+ bitmap_set_bit (non_decomposable_context, regno);
+ return -1;
+ }
}
else if (REG_P (x))
{
reg = regno_reg_rtx[regno];
regno_reg_rtx[regno] = NULL_RTX;
- clear_reg_info_regno (regno);
words = GET_MODE_SIZE (GET_MODE (reg));
words = (words + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
that the note must be removed. */
if (!x)
{
- gcc_assert(!insn);
+ gcc_assert (!insn);
return 1;
}
return 0;
}
+/* We are deleting INSN. Move any EH_REGION notes to INSNS. */
+
+static void
+move_eh_region_note (rtx insn, rtx insns)
+{
+ rtx note, p;
+
+ note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+ if (note == NULL_RTX)
+ return;
+
+ gcc_assert (CALL_P (insn)
+ || (flag_non_call_exceptions && may_trap_p (PATTERN (insn))));
+
+ for (p = insns; p != NULL_RTX; p = NEXT_INSN (p))
+ {
+ if (CALL_P (p)
+ || (flag_non_call_exceptions
+ && INSN_P (p)
+ && may_trap_p (PATTERN (p))))
+ REG_NOTES (p) = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (note, 0),
+ REG_NOTES (p));
+ }
+}
+
/* If there is a REG_LIBCALL note on OLD_START, move it to NEW_START,
and link the corresponding REG_RETVAL note to NEW_START. */
note = find_reg_equal_equiv_note (insn);
if (note)
{
+ int old_count = num_validated_changes ();
if (for_each_rtx (&XEXP (note, 0), resolve_subreg_use, NULL))
{
remove_note (insn, note);
remove_retval_note (insn);
}
+ else
+ if (old_count != num_validated_changes ())
+ df_notes_rescan (insn);
}
pnote = ®_NOTES (insn);
switch (REG_NOTE_KIND (note))
{
case REG_NO_CONFLICT:
+ case REG_DEAD:
+ case REG_UNUSED:
if (resolve_reg_p (XEXP (note, 0)))
delete = true;
break;
return insn;
}
+ /* It's possible for the code to use a subreg of a decomposed
+ register while forming an address. We need to handle that before
+ passing the address to emit_move_insn. We pass NULL_RTX as the
+ insn parameter to resolve_subreg_use because we can not validate
+ the insn yet. */
+ if (MEM_P (src) || MEM_P (dest))
+ {
+ int acg;
+
+ if (MEM_P (src))
+ for_each_rtx (&XEXP (src, 0), resolve_subreg_use, NULL_RTX);
+ if (MEM_P (dest))
+ for_each_rtx (&XEXP (dest, 0), resolve_subreg_use, NULL_RTX);
+ acg = apply_change_group ();
+ gcc_assert (acg);
+ }
+
/* If SRC is a register which we can't decompose, or has side
effects, we need to move via a temporary register. */
insns = get_insns ();
end_sequence ();
+ move_eh_region_note (insn, insns);
+
emit_insn_before (insns, insn);
move_libcall_note (insn, insns);
rtx reg;
enum machine_mode orig_mode;
unsigned int words, i;
+ int ret;
reg = XEXP (pat, 0);
if (!resolve_reg_p (reg) && !resolve_subreg_p (reg))
words = GET_MODE_SIZE (orig_mode);
words = (words + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
- XEXP (pat, 0) = simplify_gen_subreg_concatn (word_mode, reg, orig_mode, 0);
+ ret = validate_change (NULL_RTX, &XEXP (pat, 0),
+ simplify_gen_subreg_concatn (word_mode, reg,
+ orig_mode, 0),
+ 0);
+ df_insn_rescan (insn);
+ gcc_assert (ret != 0);
+
for (i = words - 1; i > 0; --i)
{
rtx x;
pseudo-registers. */
static void
-decompose_multiword_subregs (bool update_life)
+decompose_multiword_subregs (void)
{
unsigned int max;
basic_block bb;
+ if (df)
+ df_set_flags (DF_DEFER_INSN_RESCAN);
+
max = max_reg_num ();
/* First see if there are any multi-word pseudo-registers. If there
if (!bitmap_empty_p (decomposable_context))
{
int hold_no_new_pseudos = no_new_pseudos;
- int max_regno = max_reg_num ();
- sbitmap blocks;
+ sbitmap sub_blocks;
+ unsigned int i;
+ sbitmap_iterator sbi;
bitmap_iterator iter;
unsigned int regno;
propagate_pseudo_copies ();
no_new_pseudos = 0;
- blocks = sbitmap_alloc (last_basic_block);
- sbitmap_zero (blocks);
+ sub_blocks = sbitmap_alloc (last_basic_block);
+ sbitmap_zero (sub_blocks);
EXECUTE_IF_SET_IN_BITMAP (decomposable_context, 0, regno, iter)
decompose_register (regno);
if (set)
{
rtx orig_insn = insn;
+ bool cfi = control_flow_insn_p (insn);
+
+ /* We can end up splitting loads to multi-word pseudos
+ into separate loads to machine word size pseudos.
+ When this happens, we first had one load that can
+ throw, and after resolve_simple_move we'll have a
+ bunch of loads (at least two). All those loads may
+ trap if we can have non-call exceptions, so they
+ all will end the current basic block. We split the
+ block after the outer loop over all insns, but we
+ make sure here that we will be able to split the
+ basic block and still produce the correct control
+ flow graph for it. */
+ gcc_assert (!cfi
+ || (flag_non_call_exceptions
+ && can_throw_internal (insn)));
insn = resolve_simple_move (set, insn);
if (insn != orig_insn)
{
changed = true;
+ remove_retval_note (insn);
+
recog_memoized (insn);
extract_insn (insn);
+
+ if (cfi)
+ SET_BIT (sub_blocks, bb->index);
}
}
i = apply_change_group ();
gcc_assert (i);
+ remove_retval_note (insn);
+
changed = true;
}
}
-
- if (changed)
- {
- SET_BIT (blocks, bb->index);
- reg_scan_update (insn, next, max_regno);
- }
}
}
no_new_pseudos = hold_no_new_pseudos;
- if (update_life)
- update_life_info (blocks, UPDATE_LIFE_GLOBAL_RM_NOTES,
- PROP_DEATH_NOTES);
+ /* If we had insns to split that caused control flow insns in the middle
+ of a basic block, split those blocks now. Note that we only handle
+ the case where splitting a load has caused multiple possibly trapping
+ loads to appear. */
+ EXECUTE_IF_SET_IN_SBITMAP (sub_blocks, 0, i, sbi)
+ {
+ rtx insn, end;
+ edge fallthru;
+
+ bb = BASIC_BLOCK (i);
+ insn = BB_HEAD (bb);
+ end = BB_END (bb);
+
+ while (insn != end)
+ {
+ if (control_flow_insn_p (insn))
+ {
+ /* Split the block after insn. There will be a fallthru
+ edge, which is OK so we keep it. We have to create the
+ exception edges ourselves. */
+ fallthru = split_block (bb, insn);
+ rtl_make_eh_edge (NULL, bb, BB_END (bb));
+ bb = fallthru->dest;
+ insn = BB_HEAD (bb);
+ }
+ else
+ insn = NEXT_INSN (insn);
+ }
+ }
- sbitmap_free (blocks);
+ sbitmap_free (sub_blocks);
}
{
static unsigned int
rest_of_handle_lower_subreg (void)
{
- decompose_multiword_subregs (false);
+ decompose_multiword_subregs ();
return 0;
}
static unsigned int
rest_of_handle_lower_subreg2 (void)
{
- decompose_multiword_subregs (true);
+ decompose_multiword_subregs ();
return 0;
}
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func |
- TODO_ggc_collect, /* todo_flags_finish */
+ TODO_ggc_collect |
+ TODO_verify_flow, /* todo_flags_finish */
'u' /* letter */
};
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
+ TODO_df_finish |
TODO_dump_func |
- TODO_ggc_collect, /* todo_flags_finish */
+ TODO_ggc_collect |
+ TODO_verify_flow, /* todo_flags_finish */
'U' /* letter */
};