/* Shrink-wrapping related optimizations.
- Copyright (C) 1987-2014 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "rtl-error.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "stor-layout.h"
#include "varasm.h"
#include "stringpool.h"
#include "flags.h"
#include "except.h"
+#include "hard-reg-set.h"
#include "function.h"
+#include "rtl.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
#include "expr.h"
+#include "insn-codes.h"
#include "optabs.h"
#include "libfuncs.h"
#include "regs.h"
-#include "hard-reg-set.h"
-#include "insn-config.h"
#include "recog.h"
#include "output.h"
-#include "hashtab.h"
#include "tm_p.h"
#include "langhooks.h"
#include "target.h"
#include "gimplify.h"
#include "tree-pass.h"
#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "basic-block.h"
#include "df.h"
#include "params.h"
#include "bb-reorder.h"
#include "regcprop.h"
#include "rtl-iter.h"
-#ifdef HAVE_simple_return
/* Return true if INSN requires the stack frame to be set up.
PROLOGUE_USED contains the hard registers used in the function
basic_block next_block;
edge live_edge;
- /* Look for a simple register copy. */
- set = single_set (insn);
- if (!set)
+ /* Look for a simple register assignment. We don't use single_set here
+ because we can't deal with any CLOBBERs, USEs, or REG_UNUSED secondary
+ destinations. */
+ if (!INSN_P (insn))
+ return false;
+ set = PATTERN (insn);
+ if (GET_CODE (set) != SET)
return false;
src = SET_SRC (set);
dest = SET_DEST (set);
- if (!REG_P (src))
+ /* For the destination, we want only a register. Also disallow STACK
+ or FRAME related adjustments. They are likely part of the prologue,
+ so keep them in the entry block. */
+ if (!REG_P (dest)
+ || dest == stack_pointer_rtx
+ || dest == frame_pointer_rtx
+ || dest == hard_frame_pointer_rtx)
+ return false;
+
+ /* For the source, we want one of:
+ (1) A (non-overlapping) register
+ (2) A constant,
+ (3) An expression involving no more than one register.
+
+ That last point comes from the code following, which was originally
+ written to handle only register move operations, and still only handles
+ a single source register when checking for overlaps. Happily, the
+ same checks can be applied to expressions like (plus reg const). */
+
+ if (CONSTANT_P (src))
+ ;
+ else if (!REG_P (src))
{
- unsigned int reg_num = 0;
- unsigned int nonconstobj_num = 0;
rtx src_inner = NULL_RTX;
+ if (can_throw_internal (insn))
+ return false;
+
subrtx_var_iterator::array_type array;
FOR_EACH_SUBRTX_VAR (iter, array, src, ALL)
{
rtx x = *iter;
- if (REG_P (x))
+ switch (GET_RTX_CLASS (GET_CODE (x)))
{
- reg_num++;
- src_inner = x;
+ case RTX_CONST_OBJ:
+ case RTX_COMPARE:
+ case RTX_COMM_COMPARE:
+ case RTX_BIN_ARITH:
+ case RTX_COMM_ARITH:
+ case RTX_UNARY:
+ case RTX_TERNARY:
+ /* Constant or expression. Continue. */
+ break;
+
+ case RTX_OBJ:
+ case RTX_EXTRA:
+ switch (GET_CODE (x))
+ {
+ case UNSPEC:
+ case SUBREG:
+ case STRICT_LOW_PART:
+ case PC:
+ case LO_SUM:
+ /* Ok. Continue. */
+ break;
+
+ case REG:
+ /* Fail if we see a second inner register. */
+ if (src_inner != NULL)
+ return false;
+ src_inner = x;
+ break;
+
+ default:
+ return false;
+ }
+ break;
+
+ default:
+ return false;
}
- else if (!CONSTANT_P (x) && OBJECT_P (x))
- nonconstobj_num++;
}
- if (nonconstobj_num > 0
- || reg_num > 1)
- src = NULL_RTX;
- else if (reg_num == 1)
+ if (src_inner != NULL)
src = src_inner;
}
- if (!REG_P (dest) || src == NULL_RTX
- /* STACK or FRAME related adjustment might be part of prologue.
- So keep them in the entry block. */
- || dest == stack_pointer_rtx
- || dest == frame_pointer_rtx
- || dest == hard_frame_pointer_rtx)
- return false;
-
/* Make sure that the source register isn't defined later in BB. */
if (REG_P (src))
{
if (!df_live)
return false;
+ basic_block old_dest = live_edge->dest;
next_block = split_edge (live_edge);
/* We create a new basic block. Call df_grow_bb_info to make sure
all data structures are allocated. */
df_grow_bb_info (df_live);
- bitmap_copy (df_get_live_in (next_block), df_get_live_out (bb));
+
+ bitmap_and (df_get_live_in (next_block), df_get_live_out (bb),
+ df_get_live_in (old_dest));
df_set_bb_dirty (next_block);
/* We should not split more than once for a function. */
- gcc_assert (!(*split_p));
+ if (*split_p)
+ return false;
+
*split_p = true;
}
break;
}
- if (flag_shrink_wrap && HAVE_simple_return
+ if (SHRINK_WRAPPING_ENABLED
&& (targetm.profile_before_prologue () || !crtl->profile)
&& nonempty_prologue && !crtl->calls_eh_return)
{
if (frame_pointer_needed)
add_to_hard_reg_set (&set_up_by_prologue.set, Pmode,
HARD_FRAME_POINTER_REGNUM);
- if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
+ if (pic_offset_table_rtx
+ && (unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
add_to_hard_reg_set (&set_up_by_prologue.set, Pmode,
PIC_OFFSET_TABLE_REGNUM);
if (crtl->drap_reg)
FOR_EACH_BB_REVERSE_FN (bb, cfun)
{
basic_block copy_bb, tbb;
- rtx_insn *insert_point;
int eflags;
if (!bitmap_clear_bit (&bb_tail, bb->index))
BB_COPY_PARTITION (copy_bb, bb);
}
- insert_point = emit_note_after (NOTE_INSN_DELETED,
- BB_END (copy_bb));
+ rtx_note *insert_point = emit_note_after (NOTE_INSN_DELETED,
+ BB_END (copy_bb));
emit_barrier_after (BB_END (copy_bb));
tbb = bb;
else if (*pdest_bb == NULL)
{
basic_block bb;
- rtx_insn *start;
bb = create_basic_block (NULL, NULL, exit_pred);
BB_COPY_PARTITION (bb, e->src);
- start = emit_jump_insn_after (gen_simple_return (),
- BB_END (bb));
+ rtx_insn *ret = targetm.gen_simple_return ();
+ rtx_jump_insn *start = emit_jump_insn_after (ret, BB_END (bb));
JUMP_LABEL (start) = simple_return_rtx;
emit_barrier_after (start);
}
}
}
-
-#endif