| Index: gcc/gcc/fwprop.c
|
| diff --git a/gcc/gcc/fwprop.c b/gcc/gcc/fwprop.c
|
| index a01de13e3c7a8a4e40791a7e4fb943d9268ae0f7..7ac64aa5e001ee28096f3065de340bd512ecc07a 100644
|
| --- a/gcc/gcc/fwprop.c
|
| +++ b/gcc/gcc/fwprop.c
|
| @@ -1,5 +1,6 @@
|
| /* RTL-based forward propagation pass for GNU compiler.
|
| - Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
| + Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
|
| + Free Software Foundation, Inc.
|
| Contributed by Paolo Bonzini and Steven Bosscher.
|
|
|
| This file is part of GCC.
|
| @@ -38,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
|
| #include "target.h"
|
| #include "cfgloop.h"
|
| #include "tree-pass.h"
|
| +#include "domwalk.h"
|
|
|
|
|
| /* This pass does simple forward propagation and simplification when an
|
| @@ -100,11 +102,212 @@ along with GCC; see the file COPYING3. If not see
|
| (set (reg:QI 121) (subreg:QI (reg:SI 119) 0))
|
| (set (reg:SI 122) (plus:SI (reg:SI 118) (reg:SI 119)))
|
|
|
| - where the first two insns are now dead. */
|
| + where the first two insns are now dead.
|
| +
|
| + We used to use reaching definitions to find which uses have a
|
| + single reaching definition (sounds obvious...), but this is too
|
| + complex a problem in nasty testcases like PR33928. Now we use the
|
| + multiple definitions problem in df-problems.c. The similarity
|
| + between that problem and SSA form creation is taken further, in
|
| + that fwprop does a dominator walk to create its chains; however,
|
| + instead of creating a PHI function where multiple definitions meet
|
| + I just punt and record only singleton use-def chains, which is
|
| + all that is needed by fwprop. */
|
|
|
|
|
| static int num_changes;
|
|
|
| +DEF_VEC_P(df_ref);
|
| +DEF_VEC_ALLOC_P(df_ref,heap);
|
| +static VEC(df_ref,heap) *use_def_ref;
|
| +static VEC(df_ref,heap) *reg_defs;
|
| +static VEC(df_ref,heap) *reg_defs_stack;
|
| +
|
| +/* The MD bitmaps are trimmed to include only live registers to cut
|
| + memory usage on testcases like insn-recog.c. Track live registers
|
| + in the basic block and do not perform forward propagation if the
|
| + destination is a dead pseudo occurring in a note. */
|
| +static bitmap local_md;
|
| +static bitmap local_lr;
|
| +
|
| +/* Return the only def in USE's use-def chain, or NULL if there is
|
| + more than one def in the chain. */
|
| +
|
| +static inline df_ref
|
| +get_def_for_use (df_ref use)
|
| +{
|
| + return VEC_index (df_ref, use_def_ref, DF_REF_ID (use));
|
| +}
|
| +
|
| +
|
| +/* Update the reg_defs vector with non-partial definitions in DEF_REC.
|
| + TOP_FLAG says which artificials uses should be used, when DEF_REC
|
| + is an artificial def vector. LOCAL_MD is modified as after a
|
| + df_md_simulate_* function; we do more or less the same processing
|
| + done there, so we do not use those functions. */
|
| +
|
| +#define DF_MD_GEN_FLAGS \
|
| + (DF_REF_PARTIAL | DF_REF_CONDITIONAL | DF_REF_MAY_CLOBBER)
|
| +
|
| +static void
|
| +process_defs (df_ref *def_rec, int top_flag)
|
| +{
|
| + df_ref def;
|
| + while ((def = *def_rec++) != NULL)
|
| + {
|
| + df_ref curr_def = VEC_index (df_ref, reg_defs, DF_REF_REGNO (def));
|
| + unsigned int dregno;
|
| +
|
| + if ((DF_REF_FLAGS (def) & DF_REF_AT_TOP) != top_flag)
|
| + continue;
|
| +
|
| + dregno = DF_REF_REGNO (def);
|
| + if (curr_def)
|
| + VEC_safe_push (df_ref, heap, reg_defs_stack, curr_def);
|
| + else
|
| + {
|
| + /* Do not store anything if "transitioning" from NULL to NULL. But
|
| + otherwise, push a special entry on the stack to tell the
|
| + leave_block callback that the entry in reg_defs was NULL. */
|
| + if (DF_REF_FLAGS (def) & DF_MD_GEN_FLAGS)
|
| + ;
|
| + else
|
| + VEC_safe_push (df_ref, heap, reg_defs_stack, def);
|
| + }
|
| +
|
| + if (DF_REF_FLAGS (def) & DF_MD_GEN_FLAGS)
|
| + {
|
| + bitmap_set_bit (local_md, dregno);
|
| + VEC_replace (df_ref, reg_defs, dregno, NULL);
|
| + }
|
| + else
|
| + {
|
| + bitmap_clear_bit (local_md, dregno);
|
| + VEC_replace (df_ref, reg_defs, dregno, def);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +/* Fill the use_def_ref vector with values for the uses in USE_REC,
|
| + taking reaching definitions info from LOCAL_MD and REG_DEFS.
|
| + TOP_FLAG says which artificials uses should be used, when USE_REC
|
| + is an artificial use vector. */
|
| +
|
| +static void
|
| +process_uses (df_ref *use_rec, int top_flag)
|
| +{
|
| + df_ref use;
|
| + while ((use = *use_rec++) != NULL)
|
| + if ((DF_REF_FLAGS (use) & DF_REF_AT_TOP) == top_flag)
|
| + {
|
| + unsigned int uregno = DF_REF_REGNO (use);
|
| + if (VEC_index (df_ref, reg_defs, uregno)
|
| + && !bitmap_bit_p (local_md, uregno)
|
| + && bitmap_bit_p (local_lr, uregno))
|
| + VEC_replace (df_ref, use_def_ref, DF_REF_ID (use),
|
| + VEC_index (df_ref, reg_defs, uregno));
|
| + }
|
| +}
|
| +
|
| +
|
| +static void
|
| +single_def_use_enter_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| + basic_block bb)
|
| +{
|
| + int bb_index = bb->index;
|
| + struct df_md_bb_info *md_bb_info = df_md_get_bb_info (bb_index);
|
| + struct df_lr_bb_info *lr_bb_info = df_lr_get_bb_info (bb_index);
|
| + rtx insn;
|
| +
|
| + bitmap_copy (local_md, md_bb_info->in);
|
| + bitmap_copy (local_lr, lr_bb_info->in);
|
| +
|
| + /* Push a marker for the leave_block callback. */
|
| + VEC_safe_push (df_ref, heap, reg_defs_stack, NULL);
|
| +
|
| + process_uses (df_get_artificial_uses (bb_index), DF_REF_AT_TOP);
|
| + process_defs (df_get_artificial_defs (bb_index), DF_REF_AT_TOP);
|
| + df_simulate_initialize_forwards (bb, local_lr);
|
| +
|
| + FOR_BB_INSNS (bb, insn)
|
| + if (INSN_P (insn))
|
| + {
|
| + unsigned int uid = INSN_UID (insn);
|
| + process_uses (DF_INSN_UID_USES (uid), 0);
|
| + process_uses (DF_INSN_UID_EQ_USES (uid), 0);
|
| + process_defs (DF_INSN_UID_DEFS (uid), 0);
|
| + df_simulate_one_insn_forwards (bb, insn, local_lr);
|
| + }
|
| +
|
| + process_uses (df_get_artificial_uses (bb_index), 0);
|
| + process_defs (df_get_artificial_defs (bb_index), 0);
|
| +}
|
| +
|
| +/* Pop the definitions created in this basic block when leaving its
|
| + dominated parts. */
|
| +
|
| +static void
|
| +single_def_use_leave_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
|
| + basic_block bb ATTRIBUTE_UNUSED)
|
| +{
|
| + df_ref saved_def;
|
| + while ((saved_def = VEC_pop (df_ref, reg_defs_stack)) != NULL)
|
| + {
|
| + unsigned int dregno = DF_REF_REGNO (saved_def);
|
| +
|
| + /* See also process_defs. */
|
| + if (saved_def == VEC_index (df_ref, reg_defs, dregno))
|
| + VEC_replace (df_ref, reg_defs, dregno, NULL);
|
| + else
|
| + VEC_replace (df_ref, reg_defs, dregno, saved_def);
|
| + }
|
| +}
|
| +
|
| +
|
| +/* Build a vector holding the reaching definitions of uses reached by a
|
| + single dominating definition. */
|
| +
|
| +static void
|
| +build_single_def_use_links (void)
|
| +{
|
| + struct dom_walk_data walk_data;
|
| +
|
| + /* We use the multiple definitions problem to compute our restricted
|
| + use-def chains. */
|
| + df_set_flags (DF_EQ_NOTES);
|
| + df_md_add_problem ();
|
| + df_note_add_problem ();
|
| + df_analyze ();
|
| + df_maybe_reorganize_use_refs (DF_REF_ORDER_BY_INSN_WITH_NOTES);
|
| +
|
| + use_def_ref = VEC_alloc (df_ref, heap, DF_USES_TABLE_SIZE ());
|
| + VEC_safe_grow_cleared (df_ref, heap, use_def_ref, DF_USES_TABLE_SIZE ());
|
| +
|
| + reg_defs = VEC_alloc (df_ref, heap, max_reg_num ());
|
| + VEC_safe_grow_cleared (df_ref, heap, reg_defs, max_reg_num ());
|
| +
|
| + reg_defs_stack = VEC_alloc (df_ref, heap, n_basic_blocks * 10);
|
| + local_md = BITMAP_ALLOC (NULL);
|
| + local_lr = BITMAP_ALLOC (NULL);
|
| +
|
| + /* Walk the dominator tree looking for single reaching definitions
|
| + dominating the uses. This is similar to how SSA form is built. */
|
| + walk_data.dom_direction = CDI_DOMINATORS;
|
| + walk_data.initialize_block_local_data = NULL;
|
| + walk_data.before_dom_children = single_def_use_enter_block;
|
| + walk_data.after_dom_children = single_def_use_leave_block;
|
| +
|
| + init_walk_dominator_tree (&walk_data);
|
| + walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
|
| + fini_walk_dominator_tree (&walk_data);
|
| +
|
| + BITMAP_FREE (local_lr);
|
| + BITMAP_FREE (local_md);
|
| + VEC_free (df_ref, heap, reg_defs);
|
| + VEC_free (df_ref, heap, reg_defs_stack);
|
| +}
|
| +
|
|
|
| /* Do not try to replace constant addresses or addresses of local and
|
| argument slots. These MEM expressions are made only once and inserted
|
| @@ -149,7 +352,7 @@ canonicalize_address (rtx x)
|
| switch (GET_CODE (x))
|
| {
|
| case ASHIFT:
|
| - if (GET_CODE (XEXP (x, 1)) == CONST_INT
|
| + if (CONST_INT_P (XEXP (x, 1))
|
| && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (GET_MODE (x))
|
| && INTVAL (XEXP (x, 1)) >= 0)
|
| {
|
| @@ -185,11 +388,12 @@ canonicalize_address (rtx x)
|
|
|
| static bool
|
| should_replace_address (rtx old_rtx, rtx new_rtx, enum machine_mode mode,
|
| - bool speed)
|
| + addr_space_t as, bool speed)
|
| {
|
| int gain;
|
|
|
| - if (rtx_equal_p (old_rtx, new_rtx) || !memory_address_p (mode, new_rtx))
|
| + if (rtx_equal_p (old_rtx, new_rtx)
|
| + || !memory_address_addr_space_p (mode, new_rtx, as))
|
| return false;
|
|
|
| /* Copy propagation is always ok. */
|
| @@ -197,7 +401,8 @@ should_replace_address (rtx old_rtx, rtx new_rtx, enum machine_mode mode,
|
| return true;
|
|
|
| /* Prefer the new address if it is less expensive. */
|
| - gain = address_cost (old_rtx, mode, speed) - address_cost (new_rtx, mode, speed);
|
| + gain = (address_cost (old_rtx, mode, as, speed)
|
| + - address_cost (new_rtx, mode, as, speed));
|
|
|
| /* If the addresses have equivalent cost, prefer the new address
|
| if it has the highest `rtx_cost'. That has the potential of
|
| @@ -365,6 +570,7 @@ propagate_rtx_1 (rtx *px, rtx old_rtx, rtx new_rtx, int flags)
|
| /* Copy propagations are always ok. Otherwise check the costs. */
|
| if (!(REG_P (old_rtx) && REG_P (new_rtx))
|
| && !should_replace_address (op0, new_op0, GET_MODE (x),
|
| + MEM_ADDR_SPACE (x),
|
| flags & PR_OPTIMIZE_FOR_SPEED))
|
| return true;
|
|
|
| @@ -469,7 +675,7 @@ propagate_rtx (rtx x, enum machine_mode mode, rtx old_rtx, rtx new_rtx,
|
|
|
| /* gen_lowpart_common will not be able to process VOIDmode entities other
|
| than CONST_INTs. */
|
| - if (GET_MODE (tem) == VOIDmode && GET_CODE (tem) != CONST_INT)
|
| + if (GET_MODE (tem) == VOIDmode && !CONST_INT_P (tem))
|
| return NULL_RTX;
|
|
|
| if (GET_MODE (tem) == VOIDmode)
|
| @@ -524,12 +730,12 @@ use_killed_between (df_ref use, rtx def_insn, rtx target_insn)
|
| int regno;
|
| df_ref def;
|
|
|
| - /* In some obscure situations we can have a def reaching a use
|
| - that is _before_ the def. In other words the def does not
|
| - dominate the use even though the use and def are in the same
|
| - basic block. This can happen when a register may be used
|
| - uninitialized in a loop. In such cases, we must assume that
|
| - DEF is not available. */
|
| + /* We used to have a def reaching a use that is _before_ the def,
|
| + with the def not dominating the use even though the use and def
|
| + are in the same basic block, when a register may be used
|
| + uninitialized in a loop. This should not happen anymore since
|
| + we do not use reaching definitions, but still we test for such
|
| + cases and assume that DEF is not available. */
|
| if (def_bb == target_bb
|
| ? DF_INSN_LUID (def_insn) >= DF_INSN_LUID (target_insn)
|
| : !dominated_by_p (CDI_DOMINATORS, target_bb, def_bb))
|
| @@ -613,17 +819,23 @@ all_uses_available_at (rtx def_insn, rtx target_insn)
|
| }
|
| else
|
| {
|
| + rtx def_reg = REG_P (SET_DEST (def_set)) ? SET_DEST (def_set) : NULL_RTX;
|
| +
|
| /* Look at all the uses of DEF_INSN, and see if they are not
|
| killed between DEF_INSN and TARGET_INSN. */
|
| for (use_rec = DF_INSN_INFO_USES (insn_info); *use_rec; use_rec++)
|
| {
|
| df_ref use = *use_rec;
|
| + if (def_reg && rtx_equal_p (DF_REF_REG (use), def_reg))
|
| + return false;
|
| if (use_killed_between (use, def_insn, target_insn))
|
| return false;
|
| }
|
| for (use_rec = DF_INSN_INFO_EQ_USES (insn_info); *use_rec; use_rec++)
|
| {
|
| df_ref use = *use_rec;
|
| + if (def_reg && rtx_equal_p (DF_REF_REG (use), def_reg))
|
| + return false;
|
| if (use_killed_between (use, def_insn, target_insn))
|
| return false;
|
| }
|
| @@ -694,7 +906,7 @@ update_df (rtx insn, rtx *loc, df_ref *use_rec, enum df_ref_type type,
|
| df_ref orig_use = use, new_use;
|
| int width = -1;
|
| int offset = -1;
|
| - enum machine_mode mode = 0;
|
| + enum machine_mode mode = VOIDmode;
|
| rtx *new_loc = find_occurrence (loc, DF_REF_REG (orig_use));
|
| use_rec++;
|
|
|
| @@ -712,11 +924,12 @@ update_df (rtx insn, rtx *loc, df_ref *use_rec, enum df_ref_type type,
|
| use was within a MEM. */
|
| new_use = df_ref_create (DF_REF_REG (orig_use), new_loc,
|
| insn, BLOCK_FOR_INSN (insn),
|
| - type, DF_REF_FLAGS (orig_use) | new_flags,
|
| + type, DF_REF_FLAGS (orig_use) | new_flags,
|
| width, offset, mode);
|
|
|
| /* Set up the use-def chain. */
|
| - df_chain_copy (new_use, DF_REF_CHAIN (orig_use));
|
| + gcc_assert (DF_REF_ID (new_use) == (int) VEC_length (df_ref, use_def_ref));
|
| + VEC_safe_push (df_ref, heap, use_def_ref, get_def_for_use (orig_use));
|
| changed = true;
|
| }
|
| if (changed)
|
| @@ -738,9 +951,14 @@ try_fwprop_subst (df_ref use, rtx *loc, rtx new_rtx, rtx def_insn, bool set_reg_
|
| int flags = DF_REF_FLAGS (use);
|
| rtx set = single_set (insn);
|
| bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
|
| - int old_cost = rtx_cost (SET_SRC (set), SET, speed);
|
| + int old_cost = 0;
|
| bool ok;
|
|
|
| + /* forward_propagate_subreg may be operating on an instruction with
|
| + multiple sets. If so, assume the cost of the new instruction is
|
| + not greater than the old one. */
|
| + if (set)
|
| + old_cost = rtx_cost (SET_SRC (set), SET, speed);
|
| if (dump_file)
|
| {
|
| fprintf (dump_file, "\nIn insn %d, replacing\n ", INSN_UID (insn));
|
| @@ -760,6 +978,7 @@ try_fwprop_subst (df_ref use, rtx *loc, rtx new_rtx, rtx def_insn, bool set_reg_
|
| }
|
|
|
| else if (DF_REF_TYPE (use) == DF_REF_REG_USE
|
| + && set
|
| && rtx_cost (SET_SRC (set), SET, speed) > old_cost)
|
| {
|
| if (dump_file)
|
| @@ -817,8 +1036,56 @@ try_fwprop_subst (df_ref use, rtx *loc, rtx new_rtx, rtx def_insn, bool set_reg_
|
| return ok;
|
| }
|
|
|
| +/* For the given single_set INSN, containing SRC known to be a
|
| + ZERO_EXTEND or SIGN_EXTEND of a register, return true if INSN
|
| + is redundant due to the register being set by a LOAD_EXTEND_OP
|
| + load from memory. */
|
| +
|
| +static bool
|
| +free_load_extend (rtx src, rtx insn)
|
| +{
|
| + rtx reg;
|
| + df_ref *use_vec;
|
| + df_ref use = 0, def;
|
| +
|
| + reg = XEXP (src, 0);
|
| +#ifdef LOAD_EXTEND_OP
|
| + if (LOAD_EXTEND_OP (GET_MODE (reg)) != GET_CODE (src))
|
| +#endif
|
| + return false;
|
| +
|
| + for (use_vec = DF_INSN_USES (insn); *use_vec; use_vec++)
|
| + {
|
| + use = *use_vec;
|
| +
|
| + if (!DF_REF_IS_ARTIFICIAL (use)
|
| + && DF_REF_TYPE (use) == DF_REF_REG_USE
|
| + && DF_REF_REG (use) == reg)
|
| + break;
|
| + }
|
| + if (!use)
|
| + return false;
|
| +
|
| + def = get_def_for_use (use);
|
| + if (!def)
|
| + return false;
|
| +
|
| + if (DF_REF_IS_ARTIFICIAL (def))
|
| + return false;
|
| +
|
| + if (NONJUMP_INSN_P (DF_REF_INSN (def)))
|
| + {
|
| + rtx patt = PATTERN (DF_REF_INSN (def));
|
| +
|
| + if (GET_CODE (patt) == SET
|
| + && GET_CODE (SET_SRC (patt)) == MEM
|
| + && rtx_equal_p (SET_DEST (patt), reg))
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
|
|
| -/* If USE is a paradoxical subreg, see if it can be replaced by a pseudo. */
|
| +/* If USE is a subreg, see if it can be replaced by a pseudo. */
|
|
|
| static bool
|
| forward_propagate_subreg (df_ref use, rtx def_insn, rtx def_set)
|
| @@ -826,30 +1093,51 @@ forward_propagate_subreg (df_ref use, rtx def_insn, rtx def_set)
|
| rtx use_reg = DF_REF_REG (use);
|
| rtx use_insn, src;
|
|
|
| - /* Only consider paradoxical subregs... */
|
| + /* Only consider subregs... */
|
| enum machine_mode use_mode = GET_MODE (use_reg);
|
| if (GET_CODE (use_reg) != SUBREG
|
| - || !REG_P (SET_DEST (def_set))
|
| - || GET_MODE_SIZE (use_mode)
|
| - <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (use_reg))))
|
| + || !REG_P (SET_DEST (def_set)))
|
| return false;
|
|
|
| - /* If this is a paradoxical SUBREG, we have no idea what value the
|
| - extra bits would have. However, if the operand is equivalent to
|
| - a SUBREG whose operand is the same as our mode, and all the modes
|
| - are within a word, we can just use the inner operand because
|
| - these SUBREGs just say how to treat the register. */
|
| - use_insn = DF_REF_INSN (use);
|
| - src = SET_SRC (def_set);
|
| - if (GET_CODE (src) == SUBREG
|
| - && REG_P (SUBREG_REG (src))
|
| - && GET_MODE (SUBREG_REG (src)) == use_mode
|
| - && subreg_lowpart_p (src)
|
| - && all_uses_available_at (def_insn, use_insn))
|
| - return try_fwprop_subst (use, DF_REF_LOC (use), SUBREG_REG (src),
|
| - def_insn, false);
|
| - else
|
| - return false;
|
| + /* If this is a paradoxical SUBREG... */
|
| + if (GET_MODE_SIZE (use_mode)
|
| + > GET_MODE_SIZE (GET_MODE (SUBREG_REG (use_reg))))
|
| + {
|
| + /* If this is a paradoxical SUBREG, we have no idea what value the
|
| + extra bits would have. However, if the operand is equivalent to
|
| + a SUBREG whose operand is the same as our mode, and all the modes
|
| + are within a word, we can just use the inner operand because
|
| + these SUBREGs just say how to treat the register. */
|
| + use_insn = DF_REF_INSN (use);
|
| + src = SET_SRC (def_set);
|
| + if (GET_CODE (src) == SUBREG
|
| + && REG_P (SUBREG_REG (src))
|
| + && GET_MODE (SUBREG_REG (src)) == use_mode
|
| + && subreg_lowpart_p (src)
|
| + && all_uses_available_at (def_insn, use_insn))
|
| + return try_fwprop_subst (use, DF_REF_LOC (use), SUBREG_REG (src),
|
| + def_insn, false);
|
| + }
|
| +
|
| + /* If this is a SUBREG of a ZERO_EXTEND or SIGN_EXTEND, and the SUBREG
|
| + is the low part of the reg being extended then just use the inner
|
| + operand. Don't do this if the ZERO_EXTEND or SIGN_EXTEND insn will
|
| + be removed due to it matching a LOAD_EXTEND_OP load from memory. */
|
| + else if (subreg_lowpart_p (use_reg))
|
| + {
|
| + use_insn = DF_REF_INSN (use);
|
| + src = SET_SRC (def_set);
|
| + if ((GET_CODE (src) == ZERO_EXTEND
|
| + || GET_CODE (src) == SIGN_EXTEND)
|
| + && REG_P (XEXP (src, 0))
|
| + && GET_MODE (XEXP (src, 0)) == use_mode
|
| + && !free_load_extend (src, def_insn)
|
| + && all_uses_available_at (def_insn, use_insn))
|
| + return try_fwprop_subst (use, DF_REF_LOC (use), XEXP (src, 0),
|
| + def_insn, false);
|
| + }
|
| +
|
| + return false;
|
| }
|
|
|
| /* Try to replace USE with SRC (defined in DEF_INSN) in __asm. */
|
| @@ -942,7 +1230,7 @@ forward_propagate_and_simplify (df_ref use, rtx def_insn, rtx def_set)
|
| if (INSN_CODE (use_insn) < 0)
|
| asm_use = asm_noperands (PATTERN (use_insn));
|
|
|
| - if (!use_set && asm_use < 0)
|
| + if (!use_set && asm_use < 0 && !DEBUG_INSN_P (use_insn))
|
| return false;
|
|
|
| /* Do not propagate into PC, CC0, etc. */
|
| @@ -999,6 +1287,11 @@ forward_propagate_and_simplify (df_ref use, rtx def_insn, rtx def_set)
|
| loc = &SET_DEST (use_set);
|
| set_reg_equal = false;
|
| }
|
| + else if (!use_set)
|
| + {
|
| + loc = &INSN_VAR_LOCATION_LOC (use_insn);
|
| + set_reg_equal = false;
|
| + }
|
| else
|
| {
|
| rtx note = find_reg_note (use_insn, REG_EQUAL, NULL_RTX);
|
| @@ -1035,7 +1328,6 @@ forward_propagate_and_simplify (df_ref use, rtx def_insn, rtx def_set)
|
| static void
|
| forward_propagate_into (df_ref use)
|
| {
|
| - struct df_link *defs;
|
| df_ref def;
|
| rtx def_insn, def_set, use_insn;
|
| rtx parent;
|
| @@ -1046,11 +1338,9 @@ forward_propagate_into (df_ref use)
|
| return;
|
|
|
| /* Only consider uses that have a single definition. */
|
| - defs = DF_REF_CHAIN (use);
|
| - if (!defs || defs->next)
|
| + def = get_def_for_use (use);
|
| + if (!def)
|
| return;
|
| -
|
| - def = defs->ref;
|
| if (DF_REF_FLAGS (def) & DF_REF_READ_WRITE)
|
| return;
|
| if (DF_REF_IS_ARTIFICIAL (def))
|
| @@ -1096,12 +1386,7 @@ fwprop_init (void)
|
| insns (sadly) if we are not working in cfglayout mode. */
|
| loop_optimizer_init (0);
|
|
|
| - /* Now set up the dataflow problem (we only want use-def chains) and
|
| - put the dataflow solver to work. */
|
| - df_set_flags (DF_EQ_NOTES);
|
| - df_chain_add_problem (DF_UD_CHAIN);
|
| - df_analyze ();
|
| - df_maybe_reorganize_use_refs (DF_REF_ORDER_BY_INSN_WITH_NOTES);
|
| + build_single_def_use_links ();
|
| df_set_flags (DF_DEFER_INSN_RESCAN);
|
| }
|
|
|
| @@ -1110,6 +1395,7 @@ fwprop_done (void)
|
| {
|
| loop_optimizer_finalize ();
|
|
|
| + VEC_free (df_ref, heap, use_def_ref);
|
| free_dominance_info (CDI_DOMINATORS);
|
| cleanup_cfg (0);
|
| delete_trivially_dead_insns (get_insns (), max_reg_num ());
|
| @@ -1118,11 +1404,9 @@ fwprop_done (void)
|
| fprintf (dump_file,
|
| "\nNumber of successful forward propagations: %d\n\n",
|
| num_changes);
|
| - df_remove_problem (df_chain);
|
| }
|
|
|
|
|
| -
|
| /* Main entry point. */
|
|
|
| static bool
|
| @@ -1187,8 +1471,6 @@ fwprop_addr (void)
|
|
|
| /* Go through all the uses. update_df will create new ones at the
|
| end, and we'll go through them as well. */
|
| - df_set_flags (DF_DEFER_INSN_RESCAN);
|
| -
|
| for (i = 0; i < DF_USES_TABLE_SIZE (); i++)
|
| {
|
| df_ref use = DF_USES_GET (i);
|
|
|