/* Decompose multiword subregs.
- Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012
+ Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@redhat.com>
Ian Lance Taylor <iant@google.com>
#include "basic-block.h"
#include "recog.h"
#include "bitmap.h"
+#include "dce.h"
#include "expr.h"
#include "except.h"
#include "regs.h"
which it can not be decomposed. */
static bitmap non_decomposable_context;
+/* Bit N in this bitmap is set if regno N is used in a subreg
+ which changes the mode but not the size. This typically happens
+ when the register accessed as a floating-point value; we want to
+ avoid generating accesses to its subwords in integer modes. */
+static bitmap subreg_context;
+
/* Bit N in the bitmap in element M of this array is set if there is a
copy from reg M to reg N. */
static VEC(bitmap,heap) *reg_copy_graph;
&& !MODES_TIEABLE_P (GET_MODE (x), GET_MODE (inner)))
{
bitmap_set_bit (non_decomposable_context, regno);
+ bitmap_set_bit (subreg_context, regno);
return -1;
}
}
unsigned int byte)
{
unsigned int inner_size;
- enum machine_mode innermode;
+ enum machine_mode innermode, partmode;
rtx part;
unsigned int final_offset;
inner_size = GET_MODE_SIZE (innermode) / XVECLEN (op, 0);
part = XVECEXP (op, 0, byte / inner_size);
+ partmode = GET_MODE (part);
+
+ /* VECTOR_CSTs in debug expressions are expanded into CONCATN instead of
+ regular CONST_VECTORs. They have vector or integer modes, depending
+ on the capabilities of the target. Cope with them. */
+ if (partmode == VOIDmode && VECTOR_MODE_P (innermode))
+ partmode = GET_MODE_INNER (innermode);
+ else if (partmode == VOIDmode)
+ {
+ enum mode_class mclass = GET_MODE_CLASS (innermode);
+ partmode = mode_for_size (inner_size * BITS_PER_UNIT, mclass, 0);
+ }
+
final_offset = byte % inner_size;
if (final_offset + GET_MODE_SIZE (outermode) > inner_size)
return NULL_RTX;
- return simplify_gen_subreg (outermode, part, GET_MODE (part), final_offset);
+ return simplify_gen_subreg (outermode, part, partmode, final_offset);
}
/* Wrapper around simplify_gen_subreg which handles CONCATN. */
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))))
- add_reg_note (p, REG_EH_REGION, XEXP (note, 0));
- }
-}
-
/* Resolve any decomposed registers which appear in register notes on
INSN. */
unsigned int regno = REGNO (x);
if (HARD_REGISTER_NUM_P (regno))
- return (validate_subreg (word_mode, GET_MODE (x), x, UNITS_PER_WORD)
- && HARD_REGNO_MODE_OK (regno, word_mode));
+ {
+ unsigned int byte, num_bytes;
+
+ num_bytes = GET_MODE_SIZE (GET_MODE (x));
+ for (byte = 0; byte < num_bytes; byte += UNITS_PER_WORD)
+ if (simplify_subreg_regno (regno, GET_MODE (x), byte, word_mode) < 0)
+ return false;
+ return true;
+ }
else
- return !bitmap_bit_p (non_decomposable_context, regno);
+ return !bitmap_bit_p (subreg_context, regno);
}
return true;
insns = get_insns ();
end_sequence ();
- move_eh_region_note (insn, insns);
+ copy_reg_eh_region_note_forward (insn, insns, NULL_RTX);
emit_insn_before (insns, insn);
offset2 = UNITS_PER_WORD * (1 - dest_reg_num);
src_offset = UNITS_PER_WORD * src_reg_num;
- if (WORDS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
- {
- offset1 += UNITS_PER_WORD - 1;
- offset2 += UNITS_PER_WORD - 1;
- src_offset += UNITS_PER_WORD - 1;
- }
-
start_sequence ();
dest_reg = simplify_gen_subreg_concatn (word_mode, SET_DEST (set),
src_reg = expand_shift (GET_CODE (op) == ASHIFT ?
LSHIFT_EXPR : RSHIFT_EXPR,
word_mode, src_reg,
- build_int_cst (NULL_TREE,
- shift_count - BITS_PER_WORD),
+ shift_count - BITS_PER_WORD,
dest_reg, 1);
}
return;
}
+ if (df)
+ run_word_dce ();
+
/* FIXME: When the dataflow branch is merged, we can change this
code to look for each multi-word pseudo-register and to find each
insn which sets or uses that register. That should be faster
decomposable_context = BITMAP_ALLOC (NULL);
non_decomposable_context = BITMAP_ALLOC (NULL);
+ subreg_context = BITMAP_ALLOC (NULL);
reg_copy_graph = VEC_alloc (bitmap, heap, max);
VEC_safe_grow (bitmap, heap, reg_copy_graph, max);
|| GET_CODE (PATTERN (insn)) == USE)
continue;
+ recog_memoized (insn);
+
if (find_decomposable_shift_zext (insn))
continue;
- recog_memoized (insn);
extract_insn (insn);
set = simple_move (insn);
FOR_BB_INSNS (bb, insn)
{
- rtx next, pat;
+ rtx pat;
if (!INSN_P (insn))
continue;
- next = NEXT_INSN (insn);
-
pat = PATTERN (insn);
if (GET_CODE (pat) == CLOBBER)
resolve_clobber (pat, insn);
basic block and still produce the correct control
flow graph for it. */
gcc_assert (!cfi
- || (flag_non_call_exceptions
+ || (cfun->can_throw_non_call_exceptions
&& can_throw_internal (insn)));
insn = resolve_simple_move (set, insn);
unsigned int i;
bitmap b;
- for (i = 0; VEC_iterate (bitmap, reg_copy_graph, i, b); ++i)
+ FOR_EACH_VEC_ELT (bitmap, reg_copy_graph, i, b)
if (b)
BITMAP_FREE (b);
}
- VEC_free (bitmap, heap, reg_copy_graph);
+ VEC_free (bitmap, heap, reg_copy_graph);
BITMAP_FREE (decomposable_context);
BITMAP_FREE (non_decomposable_context);
+ BITMAP_FREE (subreg_context);
}
\f
/* Gate function for lower subreg pass. */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func |
TODO_ggc_collect |
TODO_verify_flow /* todo_flags_finish */
}
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_df_finish | TODO_verify_rtl_sharing |
- TODO_dump_func |
TODO_ggc_collect |
TODO_verify_flow /* todo_flags_finish */
}