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:
--------------------
/* Don't handle extensions to something other then register or
subregister. */
- if (!REG_P (lhs) && !SUBREG_REG (lhs))
+ if (!REG_P (lhs) && GET_CODE (lhs) != SUBREG)
return UNKNOWN;
if (GET_CODE (rhs) != SIGN_EXTEND && GET_CODE (rhs) != ZERO_EXTEND)
edge eg = INDEX_EDGE (edge_list, e);
start_sequence ();
- emit_insn (PATTERN (expr->se_insn));
+ emit_insn (copy_insn (PATTERN (expr->se_insn)));
se_insn = get_insns ();
end_sequence ();
}
+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);
+ RTL_CONST_CALL_P (ret) = RTL_CONST_CALL_P (insn);
+ RTL_PURE_CALL_P (ret) = RTL_PURE_CALL_P (insn);
+ RTL_LOOPING_CONST_OR_PURE_CALL_P (ret)
+ = RTL_LOOPING_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;
d.to = new_pseudo_reg;
note_uses (&PATTERN (ref_copy), see_replace_src, &d);
/* Step b: Replace every instance of dest_reg with the subreg. */
- ref_copy = replace_rtx (ref_copy, dest_reg, subreg);
+ ref_copy = replace_rtx (ref_copy, dest_reg, copy_rtx (subreg));
/* Step c: Replace every use of the new pseudo register back to
dest_real_reg. */
|| 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);
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
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
/* Don't handle extensions to something other then register or
subregister. */
- if (!REG_P (lhs) && !SUBREG_REG (lhs))
+ if (!REG_P (lhs) && GET_CODE (lhs) != SUBREG)
return NOT_RELEVANT;
switch (GET_CODE (rhs))
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 instructions. */
+ uses that are in LIBCALL or RETVAL instructions. */
static void
see_update_relevancy (void)
unsigned int uid = INSN_UID (insn);
if (INSN_P (insn))
{
-
- /* If this is an insn in a libcall, do not touch the uses. */
- if (find_reg_note (insn, REG_LIBCALL_ID, NULL_RTX))
+ 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++)
{
struct df_ref *use = *use_rec;
rest_of_handle_see (void)
{
see_main ();
+ df_clear_flags (DF_DEFER_INSN_RESCAN);
+ df_process_deferred_rescans ();
run_fast_dce ();
return 0;
}
-struct tree_opt_pass pass_see =
+struct rtl_opt_pass pass_see =
{
+ {
+ RTL_PASS,
"see", /* name */
gate_handle_see, /* gate */
rest_of_handle_see, /* execute */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_df_finish |
- TODO_dump_func, /* todo_flags_finish */
- 'u' /* letter */
+ TODO_df_verify |
+ TODO_df_finish | TODO_verify_rtl_sharing |
+ TODO_dump_func /* todo_flags_finish */
+ }
};