8sa1-gcc/gcc/ra-debug.c
Jerry Quinn 4b4bf9414f alias.c (nonlocal_mentioned_p, [...]): Use, LABEL_P, JUMP_P, CALL_P, NONJUMP_INSN_P, INSN_P, NOTE_P, BARRIER_P.
2004-07-08  Jerry Quinn  <jlquinn@optonline.net>

	* alias.c (nonlocal_mentioned_p, nonlocal_referenced_p,
	nonlocal_set_p, init_alias_analysis): Use, LABEL_P, JUMP_P, CALL_P,
	NONJUMP_INSN_P, INSN_P, NOTE_P, BARRIER_P.
	* bb-reorder.c (mark_bb_for_unlikely_executed_section,
	add_labels_and_missing_jumps, find_jump_block,
	fix_crossing_unconditional_branches, add_reg_crossing_jump_notes):
	Likewise.
	* bt-load.c (btr_referenced_p, compute_defs_uses_and_gen,
	link_btr_uses, move_btr_def): Likewise.
	* builtins.c (expand_builtin_longjmp, expand_builtin_nonlocal_goto,
	expand_builtin_expect_jump): Likewise.
	* caller-save.c (save_call_clobbered_regs, insert_one_insn): Likewise.
	* calls.c (expand_call, emit_library_call_value_1): Likewise.
	* cfganal.c (forwarder_block_p): Likewise.
	* cfgbuild.c (inside_basic_block_p, count_basic_blocks,
	make_label_edge, rtl_make_eh_edge, make_edges, find_basic_blocks_1,
	find_bb_boundaries): Likewise.
	* cfgcleanup.c (try_simplify_condjump, try_forward_edges,
	merge_blocks_move_predecessor_nojumps,
	merge_blocks_move_successor_nojumps, insns_match_p,
	flow_find_cross_jump, outgoing_edges_match, try_crossjump_to_edge,
	try_optimize_cfg): Likewise.
	* cfgexpand.c (expand_block, construct_exit_block): Likewise.
	* cfglayout.c (skip_insns_after_block, label_for_bb,
	record_effective_endpoints, insn_locators_initialize,
	fixup_reorder_chain, update_unlikely_executed_notes): Likewise.
	* cfgmainloop.c (create_loop_notes): Likewise.
	* cfgrtl.c (delete_insn, delete_insn_chain,
	create_basic_block_structure, rtl_delete_block, free_bb_for_insn,
	update_bb_for_insn, rtl_merge_blocks, rtl_can_merge_blocks,
	block_label, try_redirect_by_replacing_jump, last_loop_beg_note,
	redirect_branch_edge, force_nonfallthru_and_redirect,
	rtl_tidy_fallthru_edge, back_edge_of_syntactic_loop_p,
	rtl_split_edge, commit_one_edge_insertion, print_rtl_with_bb,
	update_br_prob_note, rtl_verify_flow_info_1, rtl_verify_flow_info,
	purge_dead_edges, cfg_layout_redirect_edge_and_branch,
	cfg_layout_delete_block, cfg_layout_can_merge_blocks_p,
	cfg_layout_merge_blocks, rtl_block_ends_with_call_p,
	need_fake_edge_p, rtl_flow_call_edges_add): Likewise.
	* combine.c (combine_instructions, can_combine_p, try_combine,
	find_split_point, record_dead_and_set_regs, reg_dead_at_p,
	distribute_notes, distribute_links, insn_cuid): Likewise.
	* cse.c (fold_rtx, cse_insn, cse_around_loop,
	invalidate_skipped_block, cse_set_around_loop,
	cse_end_of_basic_block, cse_main, cse_basic_block,
	cse_condition_code_reg): Likewise.
	* cselib.c (cselib_process_insn): Likewise.
	* ddg.c (create_ddg): Likewise.
	* df.c (df_insn_refs_record, df_bb_rd_local_compute, df_insns_modify):
	Likewise.
	* dwarf2out.c (dwarf2out_stack_adjust, dwarf2out_frame_debug,
	gen_label_die, dwarf2out_var_location): Likewise.
	* emit-rtl.c (get_first_nonnote_insn, get_last_nonnote_insn,
	next_insn, previous_insn, next_nonnote_insn, prev_nonnote_insn,
	last_call_insn, active_insn_p, next_label, prev_label,
	link_cc0_insns, next_cc0_user, try_split, add_insn_after,
	add_insn_before, remove_insn, add_function_usage_to,
	reorder_insns, find_line_note, remove_unnecessary_notes,
	emit_insn_after_1, classify_insn): Likewise.
	* except.c (convert_from_eh_region_ranges_1, emit_to_new_bb_before,
	connect_post_landing_pads, sjlj_mark_call_sites,
	sjlj_emit_function_enter, sjlj_emit_function_exit, reachable_handlers,
	can_throw_internal, can_throw_external, set_nothrow_function_flags,
	convert_to_eh_region_ranges): Likewise.
	* explow.c (optimize_save_area_alloca): Likewise.
	* expr.c (expand_expr_real): Likewise.
	* final.c (insn_current_reference_address, compute_alignments,
	shorten_branches, final, scan_ahead_for_unlikely_executed_note,
	final_scan_insn, output_asm_label, leaf_function_p): Likewise.
	* flow.c (first_insn_after_basic_block_note, delete_dead_jumptables,
	propagate_block_delete_insn, propagate_one_insn,
	init_propagate_block_info, propagate_block, libcall_dead_p,
	mark_set_1, attempt_auto_inc, find_auto_inc, try_pre_increment):
	Likewise.
	* function.c (instantiate_virtual_regs,	reorder_blocks_1,
	expand_function_start, expand_function_end, contains,
	thread_prologue_and_epilogue_insns,
	reposition_prologue_and_epilogue_notes): Likewise.
	* gcse.c (constprop_register, bypass_conditional_jumps,
	insert_insn_end_bb, gcse_after_reload): Likewise.
	* genemit.c (gen_expand, gen_split): Likewise.
	* genpeep.c (gen_peephole, main): Likewise.
	* global.c (build_insn_chain): Likewise.
	* graph.c (node_data, print_rtl_graph_with_bb): Likewise.
	* haifa-sched.c (unlink_other_notes, unlink_line_notes,
	get_block_head_tail, no_real_insns_p, rm_line_notes, save_line_notes,
	restore_line_notes, rm_redundant_line_notes, rm_other_notes,
	ok_for_early_queue_removal, set_priorities, sched_init): Likewise.
	* ifcvt.c (count_bb_insns, first_active_insn, last_active_insn,
	cond_exec_process_insns, end_ifcvt_sequence, noce_process_if_block,
	merge_if_block, block_jumps_and_fallthru_p, find_if_block,
	dead_or_predicable): Likewise.
	* integrate.c (try_constants): Likewise.
	* jump.c (rebuild_jump_labels, cleanup_barriers,
	purge_line_number_notes, init_label_info, mark_all_labels,
	squeeze_notes, get_label_before, get_label_after,
	reversed_comparison_code_parts, simplejump_p, pc_set,
	returnjump_p, onlyjump_p, follow_jumps, mark_jump_label,
	delete_barrier, delete_prior_computation, delete_computation,
	delete_related_insns, delete_for_peephole, redirect_jump):
	Likewise.
	* lcm.c (optimize_mode_switching): Likewise.
	* local-alloc.c (validate_equiv_mem, update_equiv_regs, block_alloc):
	Likewise.
	* loop-doloop.c (doloop_valid_p, doloop_optimize): Likewise.
	* loop-invariant.c (find_exits, find_invariants_bb): Likewise.
	* loop-iv.c (simplify_using_assignment): Likewise.
	* loop.c (compute_luids, loop_optimize, scan_loop, libcall_other_reg,
	libcall_benefit, skip_consec_insns, move_movables, prescan_loop,
	find_and_verify_loops, labels_in_range_p, for_each_insn_in_loop,
	loop_bivs_init_find, strength_reduce, check_insn_for_bivs,
	check_insn_for_givs, check_final_value, update_giv_derive,
	basic_induction_var, product_cheap_p, check_dbra_loop,
	loop_insn_first_p, last_use_this_basic_block,
	canonicalize_condition, get_condition, loop_regs_scan, load_mems,
	try_copy_prop, LOOP_BLOCK_NUM, loop_dump_aux): Likewise.
	* modulo-sched.c (doloop_register_get, find_line_note, sms_schedule,
	sms_schedule_by_order): Likewise.
	* optabs.c (emit_no_conflict_block, emit_libcall_block): Likewise.
	* postreload.c (reload_cse_simplify_operands, reload_combine,
	reload_cse_move2add): Likewise.
	* predict.c (can_predict_insn_p, estimate_probability,
	expected_value_to_br_prob, process_note_predictions): Likewise.
	* print-rtl.c (print_rtx, print_rtl, print_rtl_single): Likewise.
	* profile.c (branch_prob): Likewise.
	* ra-build.c (live_out_1, livethrough_conflicts_bb,
	detect_webs_set_in_cond_jump): Likewise.
	* ra-debug.c (ra_print_rtx_object, ra_debug_insns,
	ra_print_rtl_with_bb): Likewise.
	* ra-rewrite.c (insert_stores, rewrite_program2): Likewise.
	* recog.c (next_insn_tests_no_inequality, find_single_use,
	split_all_insns, peephole2_optimize, if_test_bypass_p): Likewise.
	* reg-stack.c (next_flags_user, record_label_references,
	emit_swap_insn, swap_rtx_condition, subst_stack_regs,
	compensate_edge, convert_regs_1): Likewise.
	* regclass.c (scan_one_insn): Likewise.
	* regmove.c (optimize_reg_copy_1, optimize_reg_copy_2, fixup_match_2,
	regmove_optimize, fixup_match_1, single_set_for_csa,
	combine_stack_adjustments_for_block): Likewise.
	* regrename.c (build_def_use, copyprop_hardreg_forward_1): Likewise.
	* reload.c (find_reloads, find_reloads_address_1, subst_reloads,
	find_equiv_reg): Likewise.
	* reload1.c (reload, calculate_needs_all_insns, set_label_offsets,
	reload_as_needed, emit_input_reload_insns, do_output_reload,
	delete_output_reload, delete_address_reloads_1, fixup_abnormal_edges):
	Likewise.
	* reorg.c (find_end_label, emit_delay_sequence,
	delete_from_delay_slot, delete_scheduled_jump, optimize_skip,
	get_jump_flags, rare_destination, mostly_true_jump,
	try_merge_delay_insns, redundant_insn, own_thread_p,
	fill_simple_delay_slots, fill_slots_from_thread,
	fill_eager_delay_slots, relax_delay_slots, make_return_insns,
	dbr_schedule): Likewise.
	* resource.c (find_basic_block, next_insn_no_annul,
	find_dead_or_set_registers, mark_target_live_regs): Likewise.
	* rtl.h (RTX_PREV): Likewise.
	* rtlanal.c (global_reg_mentioned_p, no_labels_between_p,
	no_jumps_between_p, reg_used_between_p, reg_referenced_between_p,
	reg_set_p, find_last_value, dead_or_set_regno_p, find_reg_fusage,
	find_regno_fusage, pure_call_p, replace_label, rtx_referenced_p_1,
	tablejump_p, computed_jump_p, insns_safe_to_move_p,
	find_first_parameter_load, can_hoist_insn_p): Likewise.
	* sched-deps.c (get_condition, add_dependence, sched_analyze_2,
	sched_analyze_insn, sched_analyze, add_forward_dependence): Likewise.
	* sched-ebb.c (fix_basic_block_boundaries, add_deps_for_risky_insns,
	schedule_ebbs): Likewise.
	* sched-rgn.c (is_cfg_nonregular, find_conditional_protection,
	is_conditionally_protected, can_schedule_ready_p,
	add_branch_dependences, debug_dependencies): Likewise.
	* stmt.c (emit_nop, expand_start_case, emit_jump_if_reachable):
	Likewise.
	* unroll.c (unroll_loop, copy_loop_body, back_branch_in_range_p,
	reg_dead_after_loop, loop_find_equiv_value, loop_iterations,
	set_dominates_use, ujump_to_loop_cont): Likewise.
	* var-tracking.c (prologue_stack_adjust, vt_initialize): Likewise.
	* varasm.c (output_constant_pool_1): Likewise.

From-SVN: r84341
2004-07-09 03:29:35 +00:00

1105 lines
30 KiB
C

/* Graph coloring register allocator
Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
Contributed by Michael Matz <matz@suse.de>
and Daniel Berlin <dan@cgsoftware.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 version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License 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. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "insn-config.h"
#include "recog.h"
#include "function.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "df.h"
#include "output.h"
#include "ra.h"
#include "tm_p.h"
#include "regs.h"
/* This file contains various dumping and debug functions for
the graph coloring register allocator. */
static void ra_print_rtx_1op (FILE *, rtx);
static void ra_print_rtx_2op (FILE *, rtx);
static void ra_print_rtx_3op (FILE *, rtx);
static void ra_print_rtx_object (FILE *, rtx);
/* The hardregs as names, for debugging. */
static const char *const reg_class_names[] = REG_CLASS_NAMES;
/* Print a message to the dump file, if debug_new_regalloc and LEVEL
have any bits in common. */
void
ra_debug_msg (unsigned int level, const char *format, ...)
{
va_list ap;
va_start (ap, format);
if ((debug_new_regalloc & level) != 0 && dump_file != NULL)
vfprintf (dump_file, format, ap);
va_end (ap);
}
/* The following ra_print_xxx() functions print RTL expressions
in concise infix form. If the mode can be seen from context it's
left out. Most operators are represented by their graphical
characters, e.g. LE as "<=". Unknown constructs are currently
printed with print_inline_rtx(), which disrupts the nice layout.
Currently only the inline asm things are written this way. */
/* Print rtx X, which is a one operand rtx (op:mode (Y)), as
"op(Y)" to FILE. */
static void
ra_print_rtx_1op (FILE *file, rtx x)
{
enum rtx_code code = GET_CODE (x);
rtx op0 = XEXP (x, 0);
switch (code)
{
case NEG:
case NOT:
fputs ((code == NEG) ? "-(" : "~(", file);
ra_print_rtx (file, op0, 0);
fputs (")", file);
break;
case HIGH:
fputs ("hi(", file);
ra_print_rtx (file, op0, 0);
fputs (")", file);
break;
default:
fprintf (file, "%s", GET_RTX_NAME (code));
if (GET_MODE (x) != VOIDmode)
fprintf (file, ":%s(", GET_MODE_NAME (GET_MODE (x)));
else
fputs ("(", file);
ra_print_rtx (file, op0, 0);
fputs (")", file);
break;
}
}
/* Print rtx X, which is a two operand rtx (op:mode (Y) (Z))
as "(Y op Z)", if the operand is know, or as "op(Y, Z)", if not,
to FILE. */
static void
ra_print_rtx_2op (FILE *file, rtx x)
{
int infix = 1;
const char *opname = "shitop";
enum rtx_code code = GET_CODE (x);
rtx op0 = XEXP (x, 0);
rtx op1 = XEXP (x, 1);
switch (code)
{
/* class '2' */
case COMPARE: opname = "?"; break;
case MINUS: opname = "-"; break;
case DIV: opname = "/"; break;
case UDIV: opname = "u/"; break;
case MOD: opname = "%"; break;
case UMOD: opname = "u%"; break;
case ASHIFT: opname = "<<"; break;
case ASHIFTRT: opname = "a>>"; break;
case LSHIFTRT: opname = "l>>"; break;
/* class 'c' */
case PLUS: opname = "+"; break;
case MULT: opname = "*"; break;
case AND: opname = "&"; break;
case IOR: opname = "|"; break;
case XOR: opname = "^"; break;
/* class '=' */
case NE: opname = "!="; break;
case EQ: opname = "=="; break;
case LTGT: opname = "<>"; break;
/* class '<' */
case GE: opname = "s>="; break;
case GT: opname = "s>"; break;
case LE: opname = "s<="; break;
case LT: opname = "s<"; break;
case GEU: opname = "u>="; break;
case GTU: opname = "u>"; break;
case LEU: opname = "u<="; break;
case LTU: opname = "u<"; break;
default:
infix = 0;
opname = GET_RTX_NAME (code);
break;
}
if (infix)
{
fputs ("(", file);
ra_print_rtx (file, op0, 0);
fprintf (file, " %s ", opname);
ra_print_rtx (file, op1, 0);
fputs (")", file);
}
else
{
fprintf (file, "%s(", opname);
ra_print_rtx (file, op0, 0);
fputs (", ", file);
ra_print_rtx (file, op1, 0);
fputs (")", file);
}
}
/* Print rtx X, which a three operand rtx to FILE.
I.e. X is either an IF_THEN_ELSE, or a bitmap operation. */
static void
ra_print_rtx_3op (FILE *file, rtx x)
{
enum rtx_code code = GET_CODE (x);
rtx op0 = XEXP (x, 0);
rtx op1 = XEXP (x, 1);
rtx op2 = XEXP (x, 2);
if (code == IF_THEN_ELSE)
{
ra_print_rtx (file, op0, 0);
fputs (" ? ", file);
ra_print_rtx (file, op1, 0);
fputs (" : ", file);
ra_print_rtx (file, op2, 0);
}
else
{
/* Bitmap-operation */
fprintf (file, "%s:%s(", GET_RTX_NAME (code),
GET_MODE_NAME (GET_MODE (x)));
ra_print_rtx (file, op0, 0);
fputs (", ", file);
ra_print_rtx (file, op1, 0);
fputs (", ", file);
ra_print_rtx (file, op2, 0);
fputs (")", file);
}
}
/* Print rtx X, which represents an object (class 'o', 'C', or some constructs
of class 'x' (e.g. subreg)), to FILE.
(reg XX) rtl is represented as "pXX", of XX was a pseudo,
as "name" it name is the nonnull hardreg name, or as "hXX", if XX
is a hardreg, whose name is NULL, or empty. */
static void
ra_print_rtx_object (FILE *file, rtx x)
{
enum rtx_code code = GET_CODE (x);
enum machine_mode mode = GET_MODE (x);
switch (code)
{
case CONST_INT:
fprintf (file, HOST_WIDE_INT_PRINT_DEC, XWINT (x, 0));
break;
case CONST_DOUBLE:
{
int i, num = 0;
const char *fmt = GET_RTX_FORMAT (code);
fputs ("dbl(", file);
for (i = 0; i < GET_RTX_LENGTH (code); i++)
{
if (num)
fputs (", ", file);
if (fmt[i] == 'e' && XEXP (x, i))
/* The MEM or other stuff */
{
ra_print_rtx (file, XEXP (x, i), 0);
num++;
}
else if (fmt[i] == 'w')
{
fprintf (file, HOST_WIDE_INT_PRINT_HEX, XWINT (x, i));
num++;
}
}
break;
}
case CONST_STRING: fprintf (file, "\"%s\"", XSTR (x, 0)); break;
case CONST: fputs ("const(", file);
ra_print_rtx (file, XEXP (x, 0), 0);
fputs (")", file);
break;
case PC: fputs ("pc", file); break;
case REG:
{
int regno = REGNO (x);
if (regno < FIRST_PSEUDO_REGISTER)
{
int i, nregs = hard_regno_nregs[regno][mode];
if (nregs > 1)
fputs ("[", file);
for (i = 0; i < nregs; i++)
{
if (i)
fputs (", ", file);
if (reg_names[regno+i] && *reg_names[regno + i])
fprintf (file, "%s", reg_names[regno + i]);
else
fprintf (file, "h%d", regno + i);
}
if (nregs > 1)
fputs ("]", file);
}
else
fprintf (file, "p%d", regno);
break;
}
case SUBREG:
{
rtx sub = SUBREG_REG (x);
int ofs = SUBREG_BYTE (x);
if (REG_P (sub)
&& REGNO (sub) < FIRST_PSEUDO_REGISTER)
{
int regno = REGNO (sub);
int i, nregs = hard_regno_nregs[regno][mode];
regno += subreg_regno_offset (regno, GET_MODE (sub),
ofs, mode);
if (nregs > 1)
fputs ("[", file);
for (i = 0; i < nregs; i++)
{
if (i)
fputs (", ", file);
if (reg_names[regno+i])
fprintf (file, "%s", reg_names[regno + i]);
else
fprintf (file, "h%d", regno + i);
}
if (nregs > 1)
fputs ("]", file);
}
else
{
ra_print_rtx (file, sub, 0);
fprintf (file, ":[%s+%d]", GET_MODE_NAME (mode), ofs);
}
break;
}
case SCRATCH: fputs ("scratch", file); break;
case CONCAT: ra_print_rtx_2op (file, x); break;
case HIGH: ra_print_rtx_1op (file, x); break;
case LO_SUM:
fputs ("(", file);
ra_print_rtx (file, XEXP (x, 0), 0);
fputs (" + lo(", file);
ra_print_rtx (file, XEXP (x, 1), 0);
fputs ("))", file);
break;
case MEM: fputs ("[", file);
ra_print_rtx (file, XEXP (x, 0), 0);
fprintf (file, "]:%s", GET_MODE_NAME (GET_MODE (x)));
/* XXX print alias set too ?? */
break;
case LABEL_REF:
{
rtx sub = XEXP (x, 0);
if (NOTE_P (sub)
&& NOTE_LINE_NUMBER (sub) == NOTE_INSN_DELETED_LABEL)
fprintf (file, "(deleted uid=%d)", INSN_UID (sub));
else if (LABEL_P (sub))
fprintf (file, "L%d", CODE_LABEL_NUMBER (sub));
else
fprintf (file, "(nonlabel uid=%d)", INSN_UID (sub));
}
break;
case SYMBOL_REF:
fprintf (file, "sym(\"%s\")", XSTR (x, 0)); break;
case CC0: fputs ("cc0", file); break;
default: print_inline_rtx (file, x, 0); break;
}
}
/* Print a general rtx X to FILE in nice infix form.
If WITH_PN is set, and X is one of the toplevel constructs
(insns, notes, labels or barriers), then print also the UIDs of
the preceding and following insn. */
void
ra_print_rtx (FILE *file, rtx x, int with_pn)
{
enum rtx_code code;
int unhandled = 0;
if (!x)
return;
code = GET_CODE (x);
/* First handle the insn like constructs. */
if (INSN_P (x) || code == NOTE || code == CODE_LABEL || code == BARRIER)
{
if (INSN_P (x))
fputs (" ", file);
/* Non-insns are prefixed by a ';'. */
if (code == BARRIER)
fputs ("; ", file);
else if (code == NOTE)
/* But notes are indented very far right. */
fprintf (file, "\t\t\t\t\t; ");
else if (code == CODE_LABEL)
/* And labels have their Lxx name first, before the actual UID. */
{
fprintf (file, "L%d:\t; ", CODE_LABEL_NUMBER (x));
if (LABEL_NAME (x))
fprintf (file, "(%s) ", LABEL_NAME (x));
switch (LABEL_KIND (x))
{
case LABEL_NORMAL: break;
case LABEL_STATIC_ENTRY: fputs (" (entry)", file); break;
case LABEL_GLOBAL_ENTRY: fputs (" (global entry)", file); break;
case LABEL_WEAK_ENTRY: fputs (" (weak entry)", file); break;
default: abort();
}
fprintf (file, " [%d uses] uid=(", LABEL_NUSES (x));
}
fprintf (file, "%d", INSN_UID (x));
if (with_pn)
fprintf (file, " %d %d", PREV_INSN (x) ? INSN_UID (PREV_INSN (x)) : 0,
NEXT_INSN (x) ? INSN_UID (NEXT_INSN (x)) : 0);
if (code == BARRIER)
fputs (" -------- barrier ---------", file);
else if (code == CODE_LABEL)
fputs (")", file);
else if (code == NOTE)
{
int ln = NOTE_LINE_NUMBER (x);
if (ln >= (int) NOTE_INSN_BIAS && ln < (int) NOTE_INSN_MAX)
fprintf (file, " %s", GET_NOTE_INSN_NAME (ln));
else
{
expanded_location s;
NOTE_EXPANDED_LOCATION (s, x);
fprintf (file, " line %d", s.line);
if (s.file != NULL)
fprintf (file, ":%s", s.file);
}
}
else
{
fprintf (file, "\t");
ra_print_rtx (file, PATTERN (x), 0);
}
return;
}
switch (code)
{
/* Top-level stuff. */
case PARALLEL:
{
int j;
for (j = 0; j < XVECLEN (x, 0); j++)
{
if (j)
fputs ("\t;; ", file);
ra_print_rtx (file, XVECEXP (x, 0, j), 0);
}
break;
}
case UNSPEC: case UNSPEC_VOLATILE:
{
int j;
fprintf (file, "unspec%s(%d",
(code == UNSPEC) ? "" : "_vol", XINT (x, 1));
for (j = 0; j < XVECLEN (x, 0); j++)
{
fputs (", ", file);
ra_print_rtx (file, XVECEXP (x, 0, j), 0);
}
fputs (")", file);
break;
}
case SET:
if (GET_CODE (SET_DEST (x)) == PC)
{
if (GET_CODE (SET_SRC (x)) == IF_THEN_ELSE
&& GET_CODE (XEXP (SET_SRC(x), 2)) == PC)
{
fputs ("if ", file);
ra_print_rtx (file, XEXP (SET_SRC (x), 0), 0);
fputs (" jump ", file);
ra_print_rtx (file, XEXP (SET_SRC (x), 1), 0);
}
else
{
fputs ("jump ", file);
ra_print_rtx (file, SET_SRC (x), 0);
}
}
else
{
ra_print_rtx (file, SET_DEST (x), 0);
fputs (" <= ", file);
ra_print_rtx (file, SET_SRC (x), 0);
}
break;
case USE:
fputs ("use <= ", file);
ra_print_rtx (file, XEXP (x, 0), 0);
break;
case CLOBBER:
ra_print_rtx (file, XEXP (x, 0), 0);
fputs (" <= clobber", file);
break;
case CALL:
fputs ("call ", file);
ra_print_rtx (file, XEXP (x, 0), 0); /* Address */
fputs (" numargs=", file);
ra_print_rtx (file, XEXP (x, 1), 0); /* Num arguments */
break;
case RETURN:
fputs ("return", file);
break;
case TRAP_IF:
fputs ("if (", file);
ra_print_rtx (file, XEXP (x, 0), 0);
fputs (") trap ", file);
ra_print_rtx (file, XEXP (x, 1), 0);
break;
case RESX:
fprintf (file, "resx from region %d", XINT (x, 0));
break;
/* Different things of class 'x' */
case SUBREG: ra_print_rtx_object (file, x); break;
case STRICT_LOW_PART:
fputs ("low(", file);
ra_print_rtx (file, XEXP (x, 0), 0);
fputs (")", file);
break;
default:
unhandled = 1;
break;
}
if (!unhandled)
return;
switch (GET_RTX_CLASS (code))
{
case RTX_UNARY:
ra_print_rtx_1op (file, x);
break;
case RTX_BIN_ARITH:
case RTX_COMM_ARITH:
case RTX_COMPARE:
case RTX_COMM_COMPARE:
ra_print_rtx_2op (file, x);
break;
case RTX_TERNARY:
case RTX_BITFIELD_OPS:
ra_print_rtx_3op (file, x);
break;
case RTX_OBJ:
case RTX_CONST_OBJ:
ra_print_rtx_object (file, x);
break;
default:
print_inline_rtx (file, x, 0);
break;
}
}
/* This only calls ra_print_rtx(), but emits a final newline. */
void
ra_print_rtx_top (FILE *file, rtx x, int with_pn)
{
ra_print_rtx (file, x, with_pn);
fprintf (file, "\n");
}
/* Callable from gdb. This prints rtx X onto stderr. */
void
ra_debug_rtx (rtx x)
{
ra_print_rtx_top (stderr, x, 1);
}
/* This prints the content of basic block with index BBI.
The first and last insn are emitted with UIDs of prev and next insns. */
void
ra_debug_bbi (int bbi)
{
basic_block bb = BASIC_BLOCK (bbi);
rtx insn;
for (insn = BB_HEAD (bb); insn; insn = NEXT_INSN (insn))
{
ra_print_rtx_top (stderr, insn,
(insn == BB_HEAD (bb) || insn == BB_END (bb)));
fprintf (stderr, "\n");
if (insn == BB_END (bb))
break;
}
}
/* Beginning from INSN, emit NUM insns (if NUM is non-negative)
or emit a window of NUM insns around INSN, to stderr. */
void
ra_debug_insns (rtx insn, int num)
{
int i, count = (num == 0 ? 1 : num < 0 ? -num : num);
if (num < 0)
for (i = count / 2; i > 0 && PREV_INSN (insn); i--)
insn = PREV_INSN (insn);
for (i = count; i > 0 && insn; insn = NEXT_INSN (insn), i--)
{
if (LABEL_P (insn))
fprintf (stderr, "\n");
ra_print_rtx_top (stderr, insn, (i == count || i == 1));
}
}
/* Beginning with INSN, emit the whole insn chain into FILE.
This also outputs comments when basic blocks start or end and omits
some notes, if flag_ra_dump_notes is zero. */
void
ra_print_rtl_with_bb (FILE *file, rtx insn)
{
basic_block last_bb, bb;
unsigned int num = 0;
if (!insn)
fputs ("nil", file);
last_bb = NULL;
for (; insn; insn = NEXT_INSN (insn))
{
if (BARRIER_P (insn))
bb = NULL;
else
bb = BLOCK_FOR_INSN (insn);
if (bb != last_bb)
{
if (last_bb)
fprintf (file, ";; End of basic block %d\n", last_bb->index);
if (bb)
fprintf (file, ";; Begin of basic block %d\n", bb->index);
last_bb = bb;
}
if (LABEL_P (insn))
fputc ('\n', file);
if (NOTE_P (insn))
{
/* Ignore basic block and maybe other notes not referencing
deleted things. */
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
&& (flag_ra_dump_notes
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL))
{
ra_print_rtx_top (file, insn, (num == 0 || !NEXT_INSN (insn)));
num++;
}
}
else
{
ra_print_rtx_top (file, insn, (num == 0 || !NEXT_INSN (insn)));
num++;
}
}
}
/* Count how many insns were seen how often, while building the interference
graph, and prints the findings. */
void
dump_number_seen (void)
{
#define N 17
int num[N];
int i;
for (i = 0; i < N; i++)
num[i] = 0;
for (i = 0; i < get_max_uid (); i++)
if (number_seen[i] < N - 1)
num[number_seen[i]]++;
else
num[N - 1]++;
for (i = 0; i < N - 1; i++)
if (num[i])
ra_debug_msg (DUMP_PROCESS, "%d insns seen %d times\n", num[i], i);
if (num[N - 1])
ra_debug_msg (DUMP_PROCESS, "%d insns seen %d and more times\n", num[i],
N - 1);
ra_debug_msg (DUMP_PROCESS, "from overall %d insns\n", get_max_uid ());
#undef N
}
/* Dump the interference graph, the move list and the webs. */
void
dump_igraph (struct df *df ATTRIBUTE_UNUSED)
{
struct move_list *ml;
unsigned int def1, def2;
int num = 0;
int num2;
unsigned int i;
if (!dump_file || (debug_new_regalloc & (DUMP_IGRAPH | DUMP_WEBS)) == 0)
return;
ra_debug_msg (DUMP_IGRAPH, "conflicts:\n ");
for (def1 = 0; def1 < num_webs; def1++)
{
int num1 = num;
num2 = 0;
for (def2 = 0; def2 < num_webs; def2++)
if (def1 != def2 && TEST_BIT (igraph, igraph_index (def1, def2)))
{
if (num1 == num)
{
if (SUBWEB_P (ID2WEB (def1)))
ra_debug_msg (DUMP_IGRAPH, "%d (SUBREG %d, %d) with ", def1,
ID2WEB (def1)->regno,
SUBREG_BYTE (ID2WEB (def1)->orig_x));
else
ra_debug_msg (DUMP_IGRAPH, "%d (REG %d) with ", def1,
ID2WEB (def1)->regno);
}
if ((num2 % 9) == 8)
ra_debug_msg (DUMP_IGRAPH, "\n ");
num++;
num2++;
if (SUBWEB_P (ID2WEB (def2)))
ra_debug_msg (DUMP_IGRAPH, "%d(%d,%d) ", def2, ID2WEB (def2)->regno,
SUBREG_BYTE (ID2WEB (def2)->orig_x));
else
ra_debug_msg (DUMP_IGRAPH, "%d(%d) ", def2, ID2WEB (def2)->regno);
}
if (num1 != num)
ra_debug_msg (DUMP_IGRAPH, "\n ");
}
ra_debug_msg (DUMP_IGRAPH, "\n");
for (ml = wl_moves; ml; ml = ml->next)
if (ml->move)
{
ra_debug_msg (DUMP_IGRAPH, "move: insn %d: Web %d <-- Web %d\n",
INSN_UID (ml->move->insn), ml->move->target_web->id,
ml->move->source_web->id);
}
ra_debug_msg (DUMP_WEBS, "\nWebs:\n");
for (i = 0; i < num_webs; i++)
{
struct web *web = ID2WEB (i);
ra_debug_msg (DUMP_WEBS, " %4d : regno %3d", i, web->regno);
if (SUBWEB_P (web))
{
ra_debug_msg (DUMP_WEBS, " sub %d", SUBREG_BYTE (web->orig_x));
ra_debug_msg (DUMP_WEBS, " par %d", find_web_for_subweb (web)->id);
}
ra_debug_msg (DUMP_WEBS, " +%d (span %d, cost "
HOST_WIDE_INT_PRINT_DEC ") (%s)",
web->add_hardregs, web->span_deaths, web->spill_cost,
reg_class_names[web->regclass]);
if (web->spill_temp == 1)
ra_debug_msg (DUMP_WEBS, " (spilltemp)");
else if (web->spill_temp == 2)
ra_debug_msg (DUMP_WEBS, " (spilltem2)");
else if (web->spill_temp == 3)
ra_debug_msg (DUMP_WEBS, " (short)");
if (web->type == PRECOLORED)
ra_debug_msg (DUMP_WEBS, " (precolored, color=%d)", web->color);
else if (find_web_for_subweb (web)->num_uses == 0)
ra_debug_msg (DUMP_WEBS, " dead");
if (web->crosses_call)
ra_debug_msg (DUMP_WEBS, " xcall");
if (web->regno >= max_normal_pseudo)
ra_debug_msg (DUMP_WEBS, " stack");
ra_debug_msg (DUMP_WEBS, "\n");
}
}
/* Dump the interference graph and webs in a format easily
parsable by programs. Used to emit real world interference graph
to my custom graph colorizer. */
void
dump_igraph_machine (void)
{
unsigned int i;
if (!dump_file || (debug_new_regalloc & DUMP_IGRAPH_M) == 0)
return;
ra_debug_msg (DUMP_IGRAPH_M, "g %d %d\n", num_webs - num_subwebs,
FIRST_PSEUDO_REGISTER);
for (i = 0; i < num_webs - num_subwebs; i++)
{
struct web *web = ID2WEB (i);
struct conflict_link *cl;
int flags = 0;
int numc = 0;
int col = 0;
flags = web->spill_temp & 0xF;
flags |= ((web->type == PRECOLORED) ? 1 : 0) << 4;
flags |= (web->add_hardregs & 0xF) << 5;
for (cl = web->conflict_list; cl; cl = cl->next)
if (cl->t->id < web->id)
numc++;
ra_debug_msg (DUMP_IGRAPH_M, "n %d %d %d %d %d %d %d\n",
web->id, web->color, flags,
(unsigned int)web->spill_cost, web->num_defs, web->num_uses,
numc);
if (web->type != PRECOLORED)
{
ra_debug_msg (DUMP_IGRAPH_M, "s %d", web->id);
while (1)
{
unsigned int u = 0;
int n;
for (n = 0; n < 32 && col < FIRST_PSEUDO_REGISTER; n++, col++)
if (TEST_HARD_REG_BIT (web->usable_regs, col))
u |= 1 << n;
ra_debug_msg (DUMP_IGRAPH_M, " %u", u);
if (col >= FIRST_PSEUDO_REGISTER)
break;
}
ra_debug_msg (DUMP_IGRAPH_M, "\n");
}
if (numc)
{
ra_debug_msg (DUMP_IGRAPH_M, "c %d", web->id);
for (cl = web->conflict_list; cl; cl = cl->next)
{
if (cl->t->id < web->id)
ra_debug_msg (DUMP_IGRAPH_M, " %d", cl->t->id);
}
ra_debug_msg (DUMP_IGRAPH_M, "\n");
}
}
ra_debug_msg (DUMP_IGRAPH_M, "e\n");
}
/* This runs after colorization and changing the insn stream.
It temporarily replaces all pseudo registers with their colors,
and emits information, if the resulting insns are strictly valid. */
void
dump_constraints (void)
{
rtx insn;
int i;
if (!dump_file || (debug_new_regalloc & DUMP_CONSTRAINTS) == 0)
return;
for (i = FIRST_PSEUDO_REGISTER; i < ra_max_regno; i++)
if (regno_reg_rtx[i] && REG_P (regno_reg_rtx[i]))
REGNO (regno_reg_rtx[i])
= ra_reg_renumber[i] >= 0 ? ra_reg_renumber[i] : i;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
int code;
int uid = INSN_UID (insn);
int o;
/* Don't simply force rerecognition, as combine might left us
with some unrecognizable ones, which later leads to aborts
in regclass, if we now destroy the remembered INSN_CODE(). */
/*INSN_CODE (insn) = -1;*/
code = recog_memoized (insn);
if (code < 0)
{
ra_debug_msg (DUMP_CONSTRAINTS,
"%d: asm insn or not recognizable.\n", uid);
continue;
}
ra_debug_msg (DUMP_CONSTRAINTS,
"%d: code %d {%s}, %d operands, constraints: ",
uid, code, insn_data[code].name, recog_data.n_operands);
extract_insn (insn);
/*preprocess_constraints ();*/
for (o = 0; o < recog_data.n_operands; o++)
{
ra_debug_msg (DUMP_CONSTRAINTS,
"%d:%s ", o, recog_data.constraints[o]);
}
if (constrain_operands (1))
ra_debug_msg (DUMP_CONSTRAINTS, "matches strictly alternative %d",
which_alternative);
else
ra_debug_msg (DUMP_CONSTRAINTS, "doesn't match strictly");
ra_debug_msg (DUMP_CONSTRAINTS, "\n");
}
for (i = FIRST_PSEUDO_REGISTER; i < ra_max_regno; i++)
if (regno_reg_rtx[i] && REG_P (regno_reg_rtx[i]))
REGNO (regno_reg_rtx[i]) = i;
}
/* This counts and emits the cumulated cost of all spilled webs,
preceded by a custom message MSG, with debug level LEVEL. */
void
dump_graph_cost (unsigned int level, const char *msg)
{
unsigned int i;
unsigned HOST_WIDE_INT cost;
if (!dump_file || (debug_new_regalloc & level) == 0)
return;
cost = 0;
for (i = 0; i < num_webs; i++)
{
struct web *web = id2web[i];
if (alias (web)->type == SPILLED)
cost += web->orig_spill_cost;
}
ra_debug_msg (level, " spill cost of graph (%s) = "
HOST_WIDE_INT_PRINT_UNSIGNED "\n",
msg ? msg : "", cost);
}
/* Dump the color assignment per web, the coalesced and spilled webs. */
void
dump_ra (struct df *df ATTRIBUTE_UNUSED)
{
struct web *web;
struct dlist *d;
if (!dump_file || (debug_new_regalloc & DUMP_RESULTS) == 0)
return;
ra_debug_msg (DUMP_RESULTS, "\nColored:\n");
for (d = WEBS(COLORED); d; d = d->next)
{
web = DLIST_WEB (d);
ra_debug_msg (DUMP_RESULTS, " %4d : color %d\n", web->id, web->color);
}
ra_debug_msg (DUMP_RESULTS, "\nCoalesced:\n");
for (d = WEBS(COALESCED); d; d = d->next)
{
web = DLIST_WEB (d);
ra_debug_msg (DUMP_RESULTS, " %4d : to web %d, color %d\n", web->id,
alias (web)->id, web->color);
}
ra_debug_msg (DUMP_RESULTS, "\nSpilled:\n");
for (d = WEBS(SPILLED); d; d = d->next)
{
web = DLIST_WEB (d);
ra_debug_msg (DUMP_RESULTS, " %4d\n", web->id);
}
ra_debug_msg (DUMP_RESULTS, "\n");
dump_cost (DUMP_RESULTS);
}
/* Calculate and dump the cumulated costs of certain types of insns
(loads, stores and copies). */
void
dump_static_insn_cost (FILE *file, const char *message, const char *prefix)
{
struct cost
{
unsigned HOST_WIDE_INT cost;
unsigned int count;
};
basic_block bb;
struct cost load, store, regcopy, selfcopy, overall;
memset (&load, 0, sizeof(load));
memset (&store, 0, sizeof(store));
memset (&regcopy, 0, sizeof(regcopy));
memset (&selfcopy, 0, sizeof(selfcopy));
memset (&overall, 0, sizeof(overall));
if (!file)
return;
FOR_EACH_BB (bb)
{
unsigned HOST_WIDE_INT block_cost = bb->frequency;
rtx insn, set;
for (insn = BB_HEAD (bb); insn; insn = NEXT_INSN (insn))
{
/* Yes, yes. We don't calculate the costs precisely.
Only for "simple enough" insns. Those containing single
sets only. */
if (INSN_P (insn) && ((set = single_set (insn)) != NULL))
{
rtx src = SET_SRC (set);
rtx dest = SET_DEST (set);
struct cost *pcost = NULL;
overall.cost += block_cost;
overall.count++;
if (rtx_equal_p (src, dest))
pcost = &selfcopy;
else if (GET_CODE (src) == GET_CODE (dest)
&& ((REG_P (src))
|| (GET_CODE (src) == SUBREG
&& REG_P (SUBREG_REG (src))
&& REG_P (SUBREG_REG (dest)))))
/* XXX is dest guaranteed to be a subreg? */
pcost = &regcopy;
else
{
if (GET_CODE (src) == SUBREG)
src = SUBREG_REG (src);
if (GET_CODE (dest) == SUBREG)
dest = SUBREG_REG (dest);
if (MEM_P (src) && !MEM_P (dest)
&& memref_is_stack_slot (src))
pcost = &load;
else if (!MEM_P (src) && MEM_P (dest)
&& memref_is_stack_slot (dest))
pcost = &store;
}
if (pcost)
{
pcost->cost += block_cost;
pcost->count++;
}
}
if (insn == BB_END (bb))
break;
}
}
if (!prefix)
prefix = "";
fprintf (file, "static insn cost %s\n", message ? message : "");
fprintf (file, " %soverall:\tnum=%6d\tcost=% 8" HOST_WIDE_INT_PRINT "d\n",
prefix, overall.count, overall.cost);
fprintf (file, " %sloads:\tnum=%6d\tcost=% 8" HOST_WIDE_INT_PRINT "d\n",
prefix, load.count, load.cost);
fprintf (file, " %sstores:\tnum=%6d\tcost=% 8" HOST_WIDE_INT_PRINT "d\n",
prefix, store.count, store.cost);
fprintf (file, " %sregcopy:\tnum=%6d\tcost=% 8" HOST_WIDE_INT_PRINT "d\n",
prefix, regcopy.count, regcopy.cost);
fprintf (file, " %sselfcpy:\tnum=%6d\tcost=% 8" HOST_WIDE_INT_PRINT "d\n",
prefix, selfcopy.count, selfcopy.cost);
}
/* Returns nonzero, if WEB1 and WEB2 have some possible
hardregs in common. */
int
web_conflicts_p (struct web *web1, struct web *web2)
{
if (web1->type == PRECOLORED && web2->type == PRECOLORED)
return 0;
if (web1->type == PRECOLORED)
return TEST_HARD_REG_BIT (web2->usable_regs, web1->regno);
if (web2->type == PRECOLORED)
return TEST_HARD_REG_BIT (web1->usable_regs, web2->regno);
return hard_regs_intersect_p (&web1->usable_regs, &web2->usable_regs);
}
/* Dump all uids of insns in which WEB is mentioned. */
void
dump_web_insns (struct web *web)
{
unsigned int i;
ra_debug_msg (DUMP_EVER, "Web: %i(%i)+%i class: %s freedom: %i degree %i\n",
web->id, web->regno, web->add_hardregs,
reg_class_names[web->regclass],
web->num_freedom, web->num_conflicts);
ra_debug_msg (DUMP_EVER, " def insns:");
for (i = 0; i < web->num_defs; ++i)
{
ra_debug_msg (DUMP_EVER, " %d ", INSN_UID (web->defs[i]->insn));
}
ra_debug_msg (DUMP_EVER, "\n use insns:");
for (i = 0; i < web->num_uses; ++i)
{
ra_debug_msg (DUMP_EVER, " %d ", INSN_UID (web->uses[i]->insn));
}
ra_debug_msg (DUMP_EVER, "\n");
}
/* Dump conflicts for web WEB. */
void
dump_web_conflicts (struct web *web)
{
int num = 0;
unsigned int def2;
ra_debug_msg (DUMP_EVER, "Web: %i(%i)+%i class: %s freedom: %i degree %i\n",
web->id, web->regno, web->add_hardregs,
reg_class_names[web->regclass],
web->num_freedom, web->num_conflicts);
for (def2 = 0; def2 < num_webs; def2++)
if (TEST_BIT (igraph, igraph_index (web->id, def2)) && web->id != def2)
{
if ((num % 9) == 5)
ra_debug_msg (DUMP_EVER, "\n ");
num++;
ra_debug_msg (DUMP_EVER, " %d(%d)", def2, id2web[def2]->regno);
if (id2web[def2]->add_hardregs)
ra_debug_msg (DUMP_EVER, "+%d", id2web[def2]->add_hardregs);
if (web_conflicts_p (web, id2web[def2]))
ra_debug_msg (DUMP_EVER, "/x");
if (id2web[def2]->type == SELECT)
ra_debug_msg (DUMP_EVER, "/s");
if (id2web[def2]->type == COALESCED)
ra_debug_msg (DUMP_EVER,"/c/%d", alias (id2web[def2])->id);
}
ra_debug_msg (DUMP_EVER, "\n");
{
struct conflict_link *wl;
num = 0;
ra_debug_msg (DUMP_EVER, "By conflicts: ");
for (wl = web->conflict_list; wl; wl = wl->next)
{
struct web* w = wl->t;
if ((num % 9) == 8)
ra_debug_msg (DUMP_EVER, "\n ");
num++;
ra_debug_msg (DUMP_EVER, "%d(%d)%s ", w->id, w->regno,
web_conflicts_p (web, w) ? "+" : "");
}
ra_debug_msg (DUMP_EVER, "\n");
}
}
/* Output HARD_REG_SET to stderr. */
void
debug_hard_reg_set (HARD_REG_SET set)
{
int i;
for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
{
if (TEST_HARD_REG_BIT (set, i))
{
fprintf (stderr, "%s ", reg_names[i]);
}
}
fprintf (stderr, "\n");
}
/*
vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
*/