/* Sign extension elimination optimization for GNU compiler.
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Leehod Baruch <leehod@il.ibm.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
--Software Foundation; either version 2, or (at your option) any later
+-Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>.
Problem description:
--------------------
#include "regs.h"
#include "timevar.h"
#include "tree-pass.h"
+#include "dce.h"
/* Used to classify defs and uses according to relevancy. */
enum entry_type {
/* The insn of the ref. */
rtx insn;
/* The merged insn that was formed from the reference's insn and extensions.
- If all merges faile it remains NULL. */
+ If all merges failed, it remains NULL. */
rtx merged_insn;
/* The def extensions of the reference that were not merged with
it. */
bool mentioned;
};
-/* A data flow object that will be created once and used throughout the
- optimization. */
-static struct df *df = NULL;
/* An array of web_entries. The i'th definition in the df object is associated
with def_entry[i] */
static struct web_entry *def_entry = NULL;
rtx reg1 = NULL;
rtx reg2 = NULL;
+ /* Parallel pattern for extension not supported for the moment. */
+ if (GET_CODE (PATTERN (extension)) == PARALLEL)
+ return NULL;
+
set = single_set (extension);
if (!set)
return NULL;
if (!extension || !INSN_P (extension))
return UNKNOWN;
+ /* Parallel pattern for extension not supported for the moment. */
+ if (GET_CODE (PATTERN (extension)) == PARALLEL)
+ return NOT_RELEVANT;
+
set = single_set (extension);
if (!set)
return NOT_RELEVANT;
(the register r on both sides of the set is the same register).
And recognize it.
If the recognition failed, this is very bad, return NULL (This will abort
- the entier optimization).
+ the entire optimization).
Otherwise, return the generated instruction. */
static rtx
static int
eq_descriptor_extension (const void *p1, const void *p2)
{
- const rtx insn = (rtx) p1;
- const rtx element = (rtx) p2;
+ const_rtx const insn = (const_rtx) p1;
+ const_rtx const element = (const_rtx) p2;
rtx set1 = single_set (insn);
rtx dest_reg1;
rtx set2 = NULL;
- rtx dest_reg2 = NULL;
+ const_rtx dest_reg2 = NULL;
gcc_assert (set1 && element && (REG_P (element) || INSN_P (element)));
static hashval_t
hash_descriptor_extension (const void *p)
{
- const rtx r = (rtx) p;
+ const_rtx const r = (const_rtx) p;
rtx set, lhs;
if (r && REG_P (r))
static void
see_initialize_data_structures (void)
{
+ unsigned int max_reg = max_reg_num ();
+ unsigned int i;
+
/* Build the df object. */
- df = df_init (DF_HARD_REGS | DF_EQUIV_NOTES | DF_SUBREGS);
- df_rd_add_problem (df);
- /* df_ru_add_problem (df); */
- df_chain_add_problem (df, DF_DU_CHAIN | DF_UD_CHAIN);
- df_analyze (df);
+ df_set_flags (DF_EQ_NOTES);
+ df_chain_add_problem (DF_DU_CHAIN + DF_UD_CHAIN);
+ df_analyze ();
+ df_set_flags (DF_DEFER_INSN_RESCAN);
if (dump_file)
- df_dump (df, dump_file);
+ df_dump (dump_file);
/* Record the last basic block at the beginning of the optimization. */
last_bb = last_basic_block;
- /* Record the number of uses at the beginning of the optimization. */
- uses_num = DF_USES_SIZE (df);
- /* Record the number of definitions at the beginning of the optimization. */
- defs_num = DF_DEFS_SIZE (df);
+
+ /* Record the number of uses and defs at the beginning of the optimization. */
+ uses_num = 0;
+ defs_num = 0;
+ for (i = 0; i < max_reg; i++)
+ {
+ uses_num += DF_REG_USE_COUNT (i) + DF_REG_EQ_USE_COUNT (i);
+ defs_num += DF_REG_DEF_COUNT (i);
+ }
/* Allocate web entries array for the union-find data structure. */
def_entry = xcalloc (defs_num, sizeof (struct web_entry));
print_rtl_single (dump_file, use_se);
}
- add_insn_before (use_se, curr_ref_s->insn);
+ add_insn_before (use_se, curr_ref_s->insn, NULL);
return 1;
}
the first place. */
htab_traverse (see_pre_extension_hash, see_pre_delete_extension, NULL);
- /* At this point, we must free the DF object, since the number of basic blocks
- may change. */
- df_finish (df);
- df = NULL;
-
/* Insert extensions on edges, according to the LCM result. */
did_insert = see_pre_insert_extensions (index_map);
/* Reset the killed bit. */
RESET_BIT (ae_kill[bb_num], indx);
- if (curr_prop->first_se_after_last_def == DF_INSN_LUID (df, ref))
+ if (curr_prop->first_se_after_last_def == DF_INSN_LUID (ref))
{
/* Set the available bit. */
SET_BIT (comp[bb_num], indx);
indx = extension_expr->bitmap_index;
- if (curr_prop->first_se_before_any_def == DF_INSN_LUID (df, ref))
+ if (curr_prop->first_se_before_any_def == DF_INSN_LUID (ref))
{
/* Set the anticipatable bit. */
SET_BIT (antloc[bb_num], indx);
/* Note: there is no need to reset the killed bit since it must be zero at
this point. */
}
- else if (curr_prop->first_se_after_last_def == DF_INSN_LUID (df, ref))
+ else if (curr_prop->first_se_after_last_def == DF_INSN_LUID (ref))
{
/* Set the available bit. */
SET_BIT (comp[bb_num], indx);
/* In this function we set the register properties for the register that is
defined and extended in the reference.
The properties are defined in see_register_properties structure which is
- allocated per basic bloack and per register.
+ allocated per basic block and per register.
Later the extension is inserted into the see_pre_extension_hash for the next
phase of the optimization.
struct see_register_properties *curr_prop = NULL;
struct see_register_properties **slot_prop;
struct see_register_properties temp_prop;
- int ref_luid = DF_INSN_LUID (df, insn);
+ int ref_luid = DF_INSN_LUID (insn);
curr_bb_hash = see_bb_hash_ar[BLOCK_NUM (curr_ref_s->insn)];
if (!curr_bb_hash)
/* In this function we set the register properties for the register that is
defined but not extended in the reference.
The properties are defined in see_register_properties structure which is
- allocated per basic bloack and per register.
+ allocated per basic block and per register.
Later the extension is inserted into the see_pre_extension_hash for the next
phase of the optimization.
struct see_register_properties *curr_prop = NULL;
struct see_register_properties **slot_prop;
struct see_register_properties temp_prop;
- int ref_luid = DF_INSN_LUID (df, insn);
+ int ref_luid = DF_INSN_LUID (insn);
curr_bb_hash = see_bb_hash_ar[BLOCK_NUM (curr_ref_s->insn)];
if (!curr_bb_hash)
/* In this function we set the register properties for the register that is used
in the reference.
The properties are defined in see_register_properties structure which is
- allocated per basic bloack and per register.
+ allocated per basic block and per register.
When a redundant use extension is found it is removed from the hash of the
reference.
If the extension is non redundant it is inserted into the
struct see_register_properties **slot_prop;
struct see_register_properties temp_prop;
bool locally_redundant = false;
- int ref_luid = DF_INSN_LUID (df, insn);
+ int ref_luid = DF_INSN_LUID (insn);
curr_bb_hash = see_bb_hash_ar[BLOCK_NUM (curr_ref_s->insn)];
if (!curr_bb_hash)
else if (curr_prop->last_def < 0
&& curr_prop->first_se_before_any_def >= 0)
{
- /* In this case the extension is localy redundant. */
+ /* In this case the extension is locally redundant. */
htab_clear_slot (curr_ref_s->use_se_hash, (PTR *)slot);
locally_redundant = true;
}
else if (curr_prop->last_def >= 0
&& curr_prop->first_se_after_last_def >= 0)
{
- /* In this case the extension is localy redundant. */
+ /* In this case the extension is locally redundant. */
htab_clear_slot (curr_ref_s->use_se_hash, (PTR *)slot);
locally_redundant = true;
}
}
+static rtx
+see_copy_insn (rtx insn)
+{
+ rtx pat = copy_insn (PATTERN (insn)), ret;
+
+ if (NONJUMP_INSN_P (insn))
+ ret = make_insn_raw (pat);
+ else if (JUMP_P (insn))
+ ret = make_jump_insn_raw (pat);
+ else if (CALL_P (insn))
+ {
+ start_sequence ();
+ ret = emit_call_insn (pat);
+ end_sequence ();
+ if (CALL_INSN_FUNCTION_USAGE (insn))
+ CALL_INSN_FUNCTION_USAGE (ret)
+ = copy_rtx (CALL_INSN_FUNCTION_USAGE (insn));
+ SIBLING_CALL_P (ret) = SIBLING_CALL_P (insn);
+ CONST_OR_PURE_CALL_P (ret) = CONST_OR_PURE_CALL_P (insn);
+ }
+ else
+ gcc_unreachable ();
+ if (REG_NOTES (insn))
+ REG_NOTES (ret) = copy_rtx (REG_NOTES (insn));
+ INSN_LOCATOR (ret) = INSN_LOCATOR (insn);
+ RTX_FRAME_RELATED_P (ret) = RTX_FRAME_RELATED_P (insn);
+ PREV_INSN (ret) = NULL_RTX;
+ NEXT_INSN (ret) = NULL_RTX;
+ return ret;
+}
+
+
/* At this point the pattern is expected to be:
ref: set (dest_reg) (rhs)
struct see_replace_data d;
/* If the original insn was already merged with an extension before,
take the merged one. */
- rtx ref = (curr_ref_s->merged_insn) ? curr_ref_s->merged_insn :
- curr_ref_s->insn;
- rtx merged_ref_next = (curr_ref_s->merged_insn) ?
- NEXT_INSN (curr_ref_s->merged_insn): NULL_RTX;
- rtx ref_copy = copy_rtx (ref);
+ rtx ref = curr_ref_s->merged_insn
+ ? curr_ref_s->merged_insn : curr_ref_s->insn;
+ rtx merged_ref_next = curr_ref_s->merged_insn
+ ? NEXT_INSN (curr_ref_s->merged_insn) : NULL_RTX;
+ rtx ref_copy = see_copy_insn (ref);
rtx source_extension_reg = see_get_extension_reg (def_se, 0);
rtx dest_extension_reg = see_get_extension_reg (def_se, 1);
- rtx move_insn = NULL;
rtx set, rhs;
rtx dest_reg, dest_real_reg;
rtx new_pseudo_reg, subreg;
|| insn_invalid_p (ref_copy))
{
/* The manipulation failed. */
+ df_insn_delete (NULL, INSN_UID (ref_copy));
/* Create a new copy. */
- ref_copy = copy_rtx (ref);
+ ref_copy = see_copy_insn (ref);
+
+ if (curr_ref_s->merged_insn)
+ df_insn_delete (NULL, INSN_UID (curr_ref_s->merged_insn));
/* Create a simple move instruction that will replace the def_se. */
start_sequence ();
+ emit_insn (ref_copy);
emit_move_insn (subreg, dest_reg);
- move_insn = get_insns ();
- end_sequence ();
-
- /* Link the manipulated instruction to the newly created move instruction
- and to the former created move instructions. */
- PREV_INSN (ref_copy) = NULL_RTX;
- NEXT_INSN (ref_copy) = move_insn;
- PREV_INSN (move_insn) = ref_copy;
- NEXT_INSN (move_insn) = merged_ref_next;
if (merged_ref_next != NULL_RTX)
- PREV_INSN (merged_ref_next) = move_insn;
- curr_ref_s->merged_insn = ref_copy;
+ emit_insn (merged_ref_next);
+ curr_ref_s->merged_insn = get_insns ();
+ end_sequence ();
if (dump_file)
{
fprintf (dump_file, "Original ref:\n");
print_rtl_single (dump_file, ref);
fprintf (dump_file, "Move insn that was added:\n");
- print_rtl_single (dump_file, move_insn);
+ print_rtl_single (dump_file, NEXT_INSN (curr_ref_s->merged_insn));
}
return;
}
/* Try to simplify the new manipulated insn. */
validate_simplify_insn (ref_copy);
+ if (curr_ref_s->merged_insn)
+ df_insn_delete (NULL, INSN_UID (curr_ref_s->merged_insn));
+
/* Create a simple move instruction to assure the correctness of the code. */
start_sequence ();
+ emit_insn (ref_copy);
emit_move_insn (dest_reg, subreg);
- move_insn = get_insns ();
- end_sequence ();
-
- /* Link the manipulated instruction to the newly created move instruction and
- to the former created move instructions. */
- PREV_INSN (ref_copy) = NULL_RTX;
- NEXT_INSN (ref_copy) = move_insn;
- PREV_INSN (move_insn) = ref_copy;
- NEXT_INSN (move_insn) = merged_ref_next;
if (merged_ref_next != NULL_RTX)
- PREV_INSN (merged_ref_next) = move_insn;
- curr_ref_s->merged_insn = ref_copy;
+ emit_insn (merged_ref_next);
+ curr_ref_s->merged_insn = get_insns ();
+ end_sequence ();
if (dump_file)
{
fprintf (dump_file, "Original ref:\n");
print_rtl_single (dump_file, ref);
fprintf (dump_file, "Transformed ref:\n");
- print_rtl_single (dump_file, ref_copy);
+ print_rtl_single (dump_file, curr_ref_s->merged_insn);
fprintf (dump_file, "Move insn that was added:\n");
- print_rtl_single (dump_file, move_insn);
+ print_rtl_single (dump_file, NEXT_INSN (curr_ref_s->merged_insn));
}
}
{
struct see_ref_s *curr_ref_s = (struct see_ref_s *) b;
rtx use_se = *slot;
- rtx ref = (curr_ref_s->merged_insn) ? curr_ref_s->merged_insn :
- curr_ref_s->insn;
- rtx merged_ref_next = (curr_ref_s->merged_insn) ?
- NEXT_INSN (curr_ref_s->merged_insn): NULL_RTX;
- rtx ref_copy = copy_rtx (ref);
+ rtx ref = curr_ref_s->merged_insn
+ ? curr_ref_s->merged_insn : curr_ref_s->insn;
+ rtx merged_ref_next = curr_ref_s->merged_insn
+ ? NEXT_INSN (curr_ref_s->merged_insn) : NULL_RTX;
+ rtx ref_copy = see_copy_insn (ref);
rtx extension_set = single_set (use_se);
rtx extension_rhs = NULL;
rtx dest_extension_reg = see_get_extension_reg (use_se, 1);
/* Replacement failed. Remove the note. */
remove_note (ref_copy, note);
else
- XEXP (note, 0) = simplified_note;
+ set_unique_reg_note (ref_copy, REG_NOTE_KIND (note),
+ simplified_note);
}
if (!see_want_to_be_merged_with_extension (ref, use_se, USE_EXTENSION))
print_rtl_single (dump_file, use_se);
print_rtl_single (dump_file, ref);
}
+ df_insn_delete (NULL, INSN_UID (ref_copy));
/* Don't remove the current use_se from the use_se_hash and continue to
the next extension. */
return 1;
print_rtl_single (dump_file, ref);
}
htab_clear_slot (curr_ref_s->use_se_hash, (PTR *)slot);
- PREV_INSN (ref_copy) = NULL_RTX;
- NEXT_INSN (ref_copy) = merged_ref_next;
+
+ if (curr_ref_s->merged_insn)
+ df_insn_delete (NULL, INSN_UID (curr_ref_s->merged_insn));
+
if (merged_ref_next != NULL_RTX)
- PREV_INSN (merged_ref_next) = ref_copy;
- curr_ref_s->merged_insn = ref_copy;
+ {
+ start_sequence ();
+ emit_insn (ref_copy);
+ emit_insn (merged_ref_next);
+ curr_ref_s->merged_insn = get_insns ();
+ end_sequence ();
+ }
+ else
+ curr_ref_s->merged_insn = ref_copy;
return 1;
}
print_rtl_single (dump_file, use_se);
print_rtl_single (dump_file, ref);
}
+ df_insn_delete (NULL, INSN_UID (ref_copy));
/* Don't remove the current use_se from the use_se_hash and continue to
the next extension. */
return 1;
/* Try to simplify the new merged insn. */
validate_simplify_insn (ref_copy);
- PREV_INSN (ref_copy) = NULL_RTX;
- NEXT_INSN (ref_copy) = merged_ref_next;
+ if (curr_ref_s->merged_insn)
+ df_insn_delete (NULL, INSN_UID (curr_ref_s->merged_insn));
+
if (merged_ref_next != NULL_RTX)
- PREV_INSN (merged_ref_next) = ref_copy;
- curr_ref_s->merged_insn = ref_copy;
+ {
+ start_sequence ();
+ emit_insn (ref_copy);
+ emit_insn (merged_ref_next);
+ curr_ref_s->merged_insn = get_insns ();
+ end_sequence ();
+ }
+ else
+ curr_ref_s->merged_insn = ref_copy;
if (dump_file)
{
print_rtl_single (dump_file, use_se);
print_rtl_single (dump_file, ref);
fprintf (dump_file, "Merged instruction:\n");
- print_rtl_single (dump_file, ref_copy);
+ print_rtl_single (dump_file, curr_ref_s->merged_insn);
}
/* Remove the current use_se from the use_se_hash. This will prevent it from
ref: set (dest_reg) (rhs)
def_se: set (dest_extension_reg) (sign/zero_extend (source_extension_reg))
- where dest_reg and source_extension_reg can both be subregs (togather)
+ where dest_reg and source_extension_reg can both be subregs (together)
and (REGNO (dest_reg) == REGNO (source_extension_reg))
The merge is done by generating, simplifying and recognizing the pattern:
rtx def_se = *slot;
/* If the original insn was already merged with an extension before,
take the merged one. */
- rtx ref = (curr_ref_s->merged_insn) ? curr_ref_s->merged_insn :
- curr_ref_s->insn;
- rtx merged_ref_next = (curr_ref_s->merged_insn) ?
- NEXT_INSN (curr_ref_s->merged_insn): NULL_RTX;
- rtx ref_copy = copy_rtx (ref);
+ rtx ref = curr_ref_s->merged_insn
+ ? curr_ref_s->merged_insn : curr_ref_s->insn;
+ rtx merged_ref_next = curr_ref_s->merged_insn
+ ? NEXT_INSN (curr_ref_s->merged_insn) : NULL_RTX;
+ rtx ref_copy = see_copy_insn (ref);
rtx new_set = NULL;
rtx source_extension_reg = see_get_extension_reg (def_se, 0);
rtx dest_extension_reg = see_get_extension_reg (def_se, 1);
- rtx move_insn, *rtx_slot, subreg;
+ rtx *rtx_slot, subreg;
rtx temp_extension = NULL;
rtx simplified_temp_extension = NULL;
rtx *pat;
print_rtl_single (dump_file, def_se);
}
+ df_insn_delete (NULL, INSN_UID (ref_copy));
see_def_extension_not_merged (curr_ref_s, def_se);
/* Continue to the next extension. */
return 1;
print_rtl_single (dump_file, def_se);
}
+ df_insn_delete (NULL, INSN_UID (ref_copy));
see_def_extension_not_merged (curr_ref_s, def_se);
/* Continue to the next extension. */
return 1;
}
/* The merge succeeded! */
+ if (curr_ref_s->merged_insn)
+ df_insn_delete (NULL, INSN_UID (curr_ref_s->merged_insn));
/* Create a simple move instruction to assure the correctness of the code. */
subreg = gen_lowpart_SUBREG (source_extension_mode, dest_extension_reg);
start_sequence ();
+ emit_insn (ref_copy);
emit_move_insn (source_extension_reg, subreg);
- move_insn = get_insns ();
- end_sequence ();
-
- /* Link the merged instruction to the newly created move instruction and
- to the former created move instructions. */
- PREV_INSN (ref_copy) = NULL_RTX;
- NEXT_INSN (ref_copy) = move_insn;
- PREV_INSN (move_insn) = ref_copy;
- NEXT_INSN (move_insn) = merged_ref_next;
if (merged_ref_next != NULL_RTX)
- PREV_INSN (merged_ref_next) = move_insn;
- curr_ref_s->merged_insn = ref_copy;
+ emit_insn (merged_ref_next);
+ curr_ref_s->merged_insn = get_insns ();
+ end_sequence ();
if (dump_file)
{
print_rtl_single (dump_file, ref);
print_rtl_single (dump_file, def_se);
fprintf (dump_file, "Merged instruction:\n");
- print_rtl_single (dump_file, ref_copy);
+ print_rtl_single (dump_file, curr_ref_s->merged_insn);
fprintf (dump_file, "Move instruction that was added:\n");
- print_rtl_single (dump_file, move_insn);
+ print_rtl_single (dump_file, NEXT_INSN (curr_ref_s->merged_insn));
}
/* Remove the current def_se from the unmerged_def_se_hash and insert it to
in it. */
{
stn = splay_tree_lookup (see_bb_splay_ar[curr_bb_num],
- DF_INSN_LUID (df, ref_insn));
+ DF_INSN_LUID (ref_insn));
if (stn)
switch (type)
{
if (!stn)
{
ref_s = xmalloc (sizeof (struct see_ref_s));
- ref_s->luid = DF_INSN_LUID (df, ref_insn);
+ ref_s->luid = DF_INSN_LUID (ref_insn);
ref_s->insn = ref_insn;
ref_s->merged_insn = NULL;
/* If this is a new reference, insert it into the splay_tree. */
if (!stn)
splay_tree_insert (see_bb_splay_ar[curr_bb_num],
- DF_INSN_LUID (df, ref_insn), (splay_tree_value) ref_s);
+ DF_INSN_LUID (ref_insn), (splay_tree_value) ref_s);
return true;
}
A definition is relevant if its root has
((entry_type == SIGN_EXTENDED_DEF) || (entry_type == ZERO_EXTENDED_DEF)) and
- his source_mode is not narrower then the the roots source_mode.
+ his source_mode is not narrower then the roots source_mode.
Return the number of relevant defs or negative number if something bad had
happened and the optimization should be aborted. */
static int
-see_handle_relevant_defs (void)
+see_handle_relevant_defs (struct df_ref *ref, rtx insn)
{
- rtx insn = NULL;
- rtx se_insn = NULL;
- rtx reg = NULL;
- rtx ref_insn = NULL;
struct web_entry *root_entry = NULL;
- unsigned int i;
- int num_relevant_defs = 0;
+ rtx se_insn = NULL;
enum rtx_code extension_code;
+ rtx reg = DF_REF_REAL_REG (ref);
+ rtx ref_insn = NULL;
+ unsigned int i = DF_REF_ID (ref);
- for (i = 0; i < defs_num; i++)
- {
- insn = DF_REF_INSN (DF_DEFS_GET (df, i));
- reg = DF_REF_REAL_REG (DF_DEFS_GET (df, i));
-
- if (!insn)
- continue;
-
- if (!INSN_P (insn))
- continue;
-
- root_entry = unionfind_root (&def_entry[i]);
-
- if (ENTRY_EI (root_entry)->relevancy != SIGN_EXTENDED_DEF
- && ENTRY_EI (root_entry)->relevancy != ZERO_EXTENDED_DEF)
- /* The current web is not relevant. Continue to the next def. */
- continue;
+ root_entry = unionfind_root (&def_entry[DF_REF_ID (ref)]);
- if (root_entry->reg)
- /* It isn't possible to have two different register for the same
- web. */
- gcc_assert (rtx_equal_p (root_entry->reg, reg));
+ if (ENTRY_EI (root_entry)->relevancy != SIGN_EXTENDED_DEF
+ && ENTRY_EI (root_entry)->relevancy != ZERO_EXTENDED_DEF)
+ /* The current web is not relevant. Continue to the next def. */
+ return 0;
+
+ if (root_entry->reg)
+ /* It isn't possible to have two different register for the same
+ web. */
+ gcc_assert (rtx_equal_p (root_entry->reg, reg));
+ else
+ root_entry->reg = reg;
+
+ /* The current definition is an EXTENDED_DEF or a definition that its
+ source_mode is narrower then its web's source_mode.
+ This means that we need to generate the implicit extension explicitly
+ and store it in the current reference's merged_def_se_hash. */
+ if (ENTRY_EI (&def_entry[i])->local_relevancy == EXTENDED_DEF
+ || (ENTRY_EI (&def_entry[i])->local_source_mode <
+ ENTRY_EI (root_entry)->source_mode))
+ {
+
+ if (ENTRY_EI (root_entry)->relevancy == SIGN_EXTENDED_DEF)
+ extension_code = SIGN_EXTEND;
else
- root_entry->reg = reg;
-
- /* The current definition is an EXTENDED_DEF or a definition that its
- source_mode is narrower then its web's source_mode.
- This means that we need to generate the implicit extension explicitly
- and store it in the current reference's merged_def_se_hash. */
- if (ENTRY_EI (&def_entry[i])->local_relevancy == EXTENDED_DEF
- || (ENTRY_EI (&def_entry[i])->local_source_mode <
- ENTRY_EI (root_entry)->source_mode))
- {
- num_relevant_defs++;
-
- if (ENTRY_EI (root_entry)->relevancy == SIGN_EXTENDED_DEF)
- extension_code = SIGN_EXTEND;
- else
- extension_code = ZERO_EXTEND;
-
- se_insn =
- see_gen_normalized_extension (reg, extension_code,
- ENTRY_EI (root_entry)->source_mode);
-
- /* This is a dummy extension, mark it as deleted. */
- INSN_DELETED_P (se_insn) = 1;
-
- if (!see_store_reference_and_extension (insn, se_insn,
- IMPLICIT_DEF_EXTENSION))
- /* Something bad happened. Abort the optimization. */
- return -1;
- continue;
- }
-
- ref_insn = PREV_INSN (insn);
- gcc_assert (BLOCK_NUM (ref_insn) == BLOCK_NUM (insn));
-
- num_relevant_defs++;
-
- if (!see_store_reference_and_extension (ref_insn, insn,
- EXPLICIT_DEF_EXTENSION))
+ extension_code = ZERO_EXTEND;
+
+ se_insn =
+ see_gen_normalized_extension (reg, extension_code,
+ ENTRY_EI (root_entry)->source_mode);
+
+ /* This is a dummy extension, mark it as deleted. */
+ INSN_DELETED_P (se_insn) = 1;
+
+ if (!see_store_reference_and_extension (insn, se_insn,
+ IMPLICIT_DEF_EXTENSION))
/* Something bad happened. Abort the optimization. */
return -1;
+ return 1;
}
- return num_relevant_defs;
-}
+
+ ref_insn = PREV_INSN (insn);
+ gcc_assert (BLOCK_NUM (ref_insn) == BLOCK_NUM (insn));
+
+ if (!see_store_reference_and_extension (ref_insn, insn,
+ EXPLICIT_DEF_EXTENSION))
+ /* Something bad happened. Abort the optimization. */
+ return -1;
+ return 0;
+}
/* Go over all the uses, for each use in relevant web store its instruction as
a reference and generate an extension before it.
happened and the optimization should be aborted. */
static int
-see_handle_relevant_uses (void)
+see_handle_relevant_uses (struct df_ref *ref, rtx insn)
{
- rtx insn = NULL;
- rtx reg = NULL;
struct web_entry *root_entry = NULL;
rtx se_insn = NULL;
- unsigned int i;
- int num_relevant_uses = 0;
enum rtx_code extension_code;
+ rtx reg = DF_REF_REAL_REG (ref);
- for (i = 0; i < uses_num; i++)
- {
- insn = DF_REF_INSN (DF_USES_GET (df, i));
- reg = DF_REF_REAL_REG (DF_USES_GET (df, i));
-
- if (!insn)
- continue;
-
- if (!INSN_P (insn))
- continue;
-
- root_entry = unionfind_root (&use_entry[i]);
-
- if (ENTRY_EI (root_entry)->relevancy != SIGN_EXTENDED_DEF
- && ENTRY_EI (root_entry)->relevancy != ZERO_EXTENDED_DEF)
- /* The current web is not relevant. Continue to the next use. */
- continue;
-
- if (root_entry->reg)
- /* It isn't possible to have two different register for the same
- web. */
- gcc_assert (rtx_equal_p (root_entry->reg, reg));
- else
- root_entry->reg = reg;
-
- /* Generate the use extension. */
- if (ENTRY_EI (root_entry)->relevancy == SIGN_EXTENDED_DEF)
- extension_code = SIGN_EXTEND;
- else
- extension_code = ZERO_EXTEND;
+ root_entry = unionfind_root (&use_entry[DF_REF_ID (ref)]);
+
+ if (ENTRY_EI (root_entry)->relevancy != SIGN_EXTENDED_DEF
+ && ENTRY_EI (root_entry)->relevancy != ZERO_EXTENDED_DEF)
+ /* The current web is not relevant. Continue to the next use. */
+ return 0;
+
+ if (root_entry->reg)
+ /* It isn't possible to have two different register for the same
+ web. */
+ gcc_assert (rtx_equal_p (root_entry->reg, reg));
+ else
+ root_entry->reg = reg;
+
+ /* Generate the use extension. */
+ if (ENTRY_EI (root_entry)->relevancy == SIGN_EXTENDED_DEF)
+ extension_code = SIGN_EXTEND;
+ else
+ extension_code = ZERO_EXTEND;
+
+ se_insn =
+ see_gen_normalized_extension (reg, extension_code,
+ ENTRY_EI (root_entry)->source_mode);
+ if (!se_insn)
+ /* This is very bad, abort the transformation. */
+ return -1;
+
+ if (!see_store_reference_and_extension (insn, se_insn,
+ USE_EXTENSION))
+ /* Something bad happened. Abort the optimization. */
+ return -1;
+ return 1;
+}
- se_insn =
- see_gen_normalized_extension (reg, extension_code,
- ENTRY_EI (root_entry)->source_mode);
- if (!se_insn)
- /* This is very bad, abort the transformation. */
- return -1;
+static int
+see_handle_relevant_refs (void)
+{
+ int num_relevant_refs = 0;
+ basic_block bb;
- num_relevant_uses++;
+ FOR_ALL_BB (bb)
+ {
+ rtx insn;
+ FOR_BB_INSNS (bb, insn)
+ {
+ unsigned int uid = INSN_UID (insn);
- if (!see_store_reference_and_extension (insn, se_insn,
- USE_EXTENSION))
- /* Something bad happened. Abort the optimization. */
- return -1;
+ if (INSN_P (insn))
+ {
+ struct df_ref **use_rec;
+ struct df_ref **def_rec;
+
+ for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
+ {
+ struct df_ref *use = *use_rec;
+ int result = see_handle_relevant_uses (use, insn);
+ if (result == -1)
+ return -1;
+ num_relevant_refs += result;
+ }
+ for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
+ {
+ struct df_ref *use = *use_rec;
+ int result = see_handle_relevant_uses (use, insn);
+ if (result == -1)
+ return -1;
+ num_relevant_refs += result;
+ }
+ for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+ {
+ struct df_ref *def = *def_rec;
+ int result = see_handle_relevant_defs (def, insn);
+ if (result == -1)
+ return -1;
+ num_relevant_refs += result;
+ }
+ }
+ }
}
-
- return num_relevant_uses;
+ return num_relevant_refs;
}
-/* Updates the relevancy of all the uses.
- The information of the i'th use is stored in use_entry[i].
- Currently all the uses are relevant for the optimization except for uses that
- are in LIBCALL or RETVAL instructions. */
+/* Initialized the use_entry field for REF in INSN at INDEX with ET. */
static void
-see_update_uses_relevancy (void)
+see_update_uses_relevancy (rtx insn, struct df_ref *ref,
+ enum entry_type et, unsigned int index)
{
- rtx insn = NULL;
- rtx reg = NULL;
struct see_entry_extra_info *curr_entry_extra_info;
- enum entry_type et;
- unsigned int i;
-
- if (!df || !use_entry)
- return;
- for (i = 0; i < uses_num; i++)
+ if (dump_file)
{
-
- insn = DF_REF_INSN (DF_USES_GET (df, i));
- reg = DF_REF_REAL_REG (DF_USES_GET (df, i));
-
- et = RELEVANT_USE;
-
- if (insn)
- {
- if (!INSN_P (insn))
- et = NOT_RELEVANT;
- if (insn && find_reg_note (insn, REG_LIBCALL, NULL_RTX))
- et = NOT_RELEVANT;
- if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
- et = NOT_RELEVANT;
- }
+ rtx reg = DF_REF_REAL_REG (ref);
+ fprintf (dump_file, "u%i insn %i reg %i ",
+ index, (insn ? INSN_UID (insn) : -1), REGNO (reg));
+ if (et == NOT_RELEVANT)
+ fprintf (dump_file, "NOT RELEVANT \n");
else
- et = NOT_RELEVANT;
-
- if (dump_file)
- {
- fprintf (dump_file, "u%i insn %i reg %i ",
- i, (insn ? INSN_UID (insn) : -1), REGNO (reg));
- if (et == NOT_RELEVANT)
- fprintf (dump_file, "NOT RELEVANT \n");
- else
- fprintf (dump_file, "RELEVANT USE \n");
- }
-
- curr_entry_extra_info = xmalloc (sizeof (struct see_entry_extra_info));
- curr_entry_extra_info->relevancy = et;
- curr_entry_extra_info->local_relevancy = et;
- use_entry[i].extra_info = curr_entry_extra_info;
- use_entry[i].reg = NULL;
- use_entry[i].pred = NULL;
+ fprintf (dump_file, "RELEVANT USE \n");
}
+
+ DF_REF_ID (ref) = index;
+ curr_entry_extra_info = xmalloc (sizeof (struct see_entry_extra_info));
+ curr_entry_extra_info->relevancy = et;
+ curr_entry_extra_info->local_relevancy = et;
+ use_entry[index].extra_info = curr_entry_extra_info;
+ use_entry[index].reg = NULL;
+ use_entry[index].pred = NULL;
}
*source_mode = MAX_MACHINE_MODE;
*source_mode_unsigned = MAX_MACHINE_MODE;
- if (!insn)
- return NOT_RELEVANT;
-
- if (!INSN_P (insn))
- return NOT_RELEVANT;
-
extension_code = see_get_extension_data (insn, source_mode);
switch (extension_code)
{
relevant. Handling this extension as relevant would make things much
more complicated. */
next_insn = NEXT_INSN (insn);
- if (prev_insn
- && INSN_P (prev_insn)
+ if (next_insn
+ && INSN_P (next_insn)
&& (see_get_extension_data (next_insn, &next_source_mode) !=
NOT_RELEVANT))
{
}
-/* Updates the relevancy and source_mode of all the definitions.
- The information of the i'th definition is stored in def_entry[i]. */
+/* Initialized the def_entry field for REF in INSN at INDEX with ET. */
static void
-see_update_defs_relevancy (void)
+see_update_defs_relevancy (rtx insn, struct df_ref *ref,
+ enum entry_type et,
+ enum machine_mode source_mode,
+ enum machine_mode source_mode_unsigned,
+ unsigned int index)
{
- struct see_entry_extra_info *curr_entry_extra_info;
- unsigned int i;
- rtx insn = NULL;
- rtx reg = NULL;
- enum entry_type et;
- enum machine_mode source_mode;
- enum machine_mode source_mode_unsigned;
+ struct see_entry_extra_info *curr_entry_extra_info
+ = xmalloc (sizeof (struct see_entry_extra_info));
+ curr_entry_extra_info->relevancy = et;
+ curr_entry_extra_info->local_relevancy = et;
- if (!df || !def_entry)
- return;
+ DF_REF_ID (ref) = index;
- for (i = 0; i < defs_num; i++)
+ if (et != EXTENDED_DEF)
{
- insn = DF_REF_INSN (DF_DEFS_GET (df, i));
- reg = DF_REF_REAL_REG (DF_DEFS_GET (df, i));
-
- et = see_analyze_one_def (insn, &source_mode, &source_mode_unsigned);
-
- curr_entry_extra_info = xmalloc (sizeof (struct see_entry_extra_info));
- curr_entry_extra_info->relevancy = et;
- curr_entry_extra_info->local_relevancy = et;
- if (et != EXTENDED_DEF)
+ curr_entry_extra_info->source_mode = source_mode;
+ curr_entry_extra_info->local_source_mode = source_mode;
+ }
+ else
+ {
+ curr_entry_extra_info->source_mode_signed = source_mode;
+ curr_entry_extra_info->source_mode_unsigned = source_mode_unsigned;
+ }
+ def_entry[index].extra_info = curr_entry_extra_info;
+ def_entry[index].reg = NULL;
+ def_entry[index].pred = NULL;
+
+ if (dump_file)
+ {
+ rtx reg = DF_REF_REAL_REG (ref);
+ if (et == NOT_RELEVANT)
{
- curr_entry_extra_info->source_mode = source_mode;
- curr_entry_extra_info->local_source_mode = source_mode;
+ fprintf (dump_file, "d%i insn %i reg %i ",
+ index, (insn ? INSN_UID (insn) : -1), REGNO (reg));
+ fprintf (dump_file, "NOT RELEVANT \n");
}
else
{
- curr_entry_extra_info->source_mode_signed = source_mode;
- curr_entry_extra_info->source_mode_unsigned = source_mode_unsigned;
+ fprintf (dump_file, "d%i insn %i reg %i ",
+ index, INSN_UID (insn), REGNO (reg));
+ fprintf (dump_file, "RELEVANT - ");
+ switch (et)
+ {
+ case SIGN_EXTENDED_DEF :
+ fprintf (dump_file, "SIGN_EXTENDED_DEF, source_mode = %s\n",
+ GET_MODE_NAME (source_mode));
+ break;
+ case ZERO_EXTENDED_DEF :
+ fprintf (dump_file, "ZERO_EXTENDED_DEF, source_mode = %s\n",
+ GET_MODE_NAME (source_mode));
+ break;
+ case EXTENDED_DEF :
+ fprintf (dump_file, "EXTENDED_DEF, ");
+ if (source_mode != MAX_MACHINE_MODE
+ && source_mode_unsigned != MAX_MACHINE_MODE)
+ {
+ fprintf (dump_file, "positive const, ");
+ fprintf (dump_file, "source_mode_signed = %s, ",
+ GET_MODE_NAME (source_mode));
+ fprintf (dump_file, "source_mode_unsigned = %s\n",
+ GET_MODE_NAME (source_mode_unsigned));
+ }
+ else if (source_mode != MAX_MACHINE_MODE)
+ fprintf (dump_file, "source_mode_signed = %s\n",
+ GET_MODE_NAME (source_mode));
+ else
+ fprintf (dump_file, "source_mode_unsigned = %s\n",
+ GET_MODE_NAME (source_mode_unsigned));
+ break;
+ default :
+ gcc_unreachable ();
+ }
}
- def_entry[i].extra_info = curr_entry_extra_info;
- def_entry[i].reg = NULL;
- def_entry[i].pred = NULL;
+ }
+}
- if (dump_file)
+
+/* Updates the relevancy of all the uses and all defs.
+
+ The information of the u'th use is stored in use_entry[u] and the
+ information of the d'th definition is stored in def_entry[d].
+
+ Currently all the uses are relevant for the optimization except for
+ uses that are in LIBCALL or RETVAL instructions. */
+
+static void
+see_update_relevancy (void)
+{
+ unsigned int d = 0;
+ unsigned int u = 0;
+ enum entry_type et;
+ enum machine_mode source_mode;
+ enum machine_mode source_mode_unsigned;
+ basic_block bb;
+
+ if (!def_entry)
+ return;
+
+ FOR_ALL_BB (bb)
+ {
+ struct df_ref **use_rec;
+ struct df_ref **def_rec;
+ rtx insn;
+ FOR_BB_INSNS (bb, insn)
{
- if (et == NOT_RELEVANT)
+ unsigned int uid = INSN_UID (insn);
+ if (INSN_P (insn))
{
- fprintf (dump_file, "d%i insn %i reg %i ",
- i, (insn ? INSN_UID (insn) : -1), REGNO (reg));
- fprintf (dump_file, "NOT RELEVANT \n");
- }
- else
- {
- fprintf (dump_file, "d%i insn %i reg %i ",
- i ,INSN_UID (insn), REGNO (reg));
- fprintf (dump_file, "RELEVANT - ");
- switch (et)
+ if (find_reg_note (insn, REG_LIBCALL, NULL_RTX)
+ || find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ et = NOT_RELEVANT;
+ else
+ et = RELEVANT_USE;
+
+ for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
{
- case SIGN_EXTENDED_DEF :
- fprintf (dump_file, "SIGN_EXTENDED_DEF, source_mode = %s\n",
- GET_MODE_NAME (source_mode));
- break;
- case ZERO_EXTENDED_DEF :
- fprintf (dump_file, "ZERO_EXTENDED_DEF, source_mode = %s\n",
- GET_MODE_NAME (source_mode));
- break;
- case EXTENDED_DEF :
- fprintf (dump_file, "EXTENDED_DEF, ");
- if (source_mode != MAX_MACHINE_MODE
- && source_mode_unsigned != MAX_MACHINE_MODE)
- {
- fprintf (dump_file, "positive const, ");
- fprintf (dump_file, "source_mode_signed = %s, ",
- GET_MODE_NAME (source_mode));
- fprintf (dump_file, "source_mode_unsigned = %s\n",
- GET_MODE_NAME (source_mode_unsigned));
- }
- else if (source_mode != MAX_MACHINE_MODE)
- fprintf (dump_file, "source_mode_signed = %s\n",
- GET_MODE_NAME (source_mode));
- else
- fprintf (dump_file, "source_mode_unsigned = %s\n",
- GET_MODE_NAME (source_mode_unsigned));
- break;
- default :
- gcc_unreachable ();
+ struct df_ref *use = *use_rec;
+ see_update_uses_relevancy (insn, use, et, u);
+ u++;
+ }
+
+ for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
+ {
+ struct df_ref *use = *use_rec;
+ see_update_uses_relevancy (insn, use, et, u);
+ u++;
+ }
+
+ et = see_analyze_one_def (insn, &source_mode, &source_mode_unsigned);
+ for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++)
+ {
+ struct df_ref *def = *def_rec;
+ see_update_defs_relevancy (insn, def, et, source_mode,
+ source_mode_unsigned, d);
+ d++;
}
}
}
+
+ for (use_rec = df_get_artificial_uses (bb->index); *use_rec; use_rec++)
+ {
+ struct df_ref *use = *use_rec;
+ see_update_uses_relevancy (NULL, use, NOT_RELEVANT, u);
+ u++;
+ }
+
+ for (def_rec = df_get_artificial_defs (bb->index); *def_rec; def_rec++)
+ {
+ struct df_ref *def = *def_rec;
+ see_update_defs_relevancy (NULL, def, NOT_RELEVANT,
+ MAX_MACHINE_MODE, MAX_MACHINE_MODE, d);
+ d++;
+ }
}
}
static bool
see_propagate_extensions_to_uses (void)
{
- unsigned int i = 0;
- int num_relevant_uses;
- int num_relevant_defs;
+ int num_relevant_refs;
+ basic_block bb;
if (dump_file)
fprintf (dump_file,
"* Phase 1: Propagate extensions to uses. *\n");
/* Update the relevancy of references using the DF object. */
- see_update_defs_relevancy ();
- see_update_uses_relevancy ();
+ see_update_relevancy ();
/* Produce the webs and update the extra_info of the root.
In general, a web is relevant if all its definitions and uses are relevant
and there is at least one definition that was marked as SIGN_EXTENDED_DEF
or ZERO_EXTENDED_DEF. */
- for (i = 0; i < uses_num; i++)
- union_defs (df, DF_USES_GET (df, i), def_entry, use_entry,
- see_update_leader_extra_info);
+ FOR_ALL_BB (bb)
+ {
+ rtx insn;
+ struct df_ref **use_rec;
- /* Generate use extensions for references and insert these
- references to see_bb_splay_ar data structure. */
- num_relevant_uses = see_handle_relevant_uses ();
+ FOR_BB_INSNS (bb, insn)
+ {
+ unsigned int uid = INSN_UID (insn);
+ if (INSN_P (insn))
+ {
+ for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++)
+ {
+ struct df_ref *use = *use_rec;
+ union_defs (use, def_entry, use_entry, see_update_leader_extra_info);
+ }
+
+ for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++)
+ {
+ struct df_ref *use = *use_rec;
+ union_defs (use, def_entry, use_entry, see_update_leader_extra_info);
+ }
+ }
+ }
- if (num_relevant_uses < 0)
- return false;
+ for (use_rec = df_get_artificial_uses (bb->index); *use_rec; use_rec++)
+ {
+ struct df_ref *use = *use_rec;
+ union_defs (use, def_entry, use_entry, see_update_leader_extra_info);
+ }
+ }
- /* Store the def extensions in their references structures and insert these
+ /* Generate use extensions for references and insert these
references to see_bb_splay_ar data structure. */
- num_relevant_defs = see_handle_relevant_defs ();
-
- if (num_relevant_defs < 0)
- return false;
+ num_relevant_refs = see_handle_relevant_refs ();
- return num_relevant_uses > 0 || num_relevant_defs > 0;
+ return num_relevant_refs > 0;
}
static unsigned int
rest_of_handle_see (void)
{
- int no_new_pseudos_bcp = no_new_pseudos;
-
- no_new_pseudos = 0;
see_main ();
- no_new_pseudos = no_new_pseudos_bcp;
-
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
- update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
- (PROP_DEATH_NOTES));
- cleanup_cfg (CLEANUP_EXPENSIVE);
- reg_scan (get_insns (), max_reg_num ());
-
+ df_clear_flags (DF_DEFER_INSN_RESCAN);
+ df_process_deferred_rescans ();
+ run_fast_dce ();
return 0;
}
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
+ TODO_df_verify |
+ TODO_df_finish | TODO_verify_rtl_sharing |
TODO_dump_func, /* todo_flags_finish */
'u' /* letter */
};