#include "config.h"
#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "tm_p.h"
#include "regs.h"
#include "insn-config.h"
#include "insn-attr.h"
#include "recog.h"
#include "conditions.h"
#include "flags.h"
#include "real.h"
#include "hard-reg-set.h"
#include "output.h"
#include "except.h"
#include "function.h"
#include "toplev.h"
#include "reload.h"
#include "intl.h"
#include "basic-block.h"
#include "target.h"
#include "debug.h"
#include "expr.h"
#include "profile.h"
#include "cfglayout.h"
#include "feedback.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#endif
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
#include "dwarf2out.h"
#endif
#ifndef CC_STATUS_INIT
#define CC_STATUS_INIT
#endif
#ifndef ASM_COMMENT_START
#define ASM_COMMENT_START ";#"
#endif
#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
#endif
#ifndef JUMP_TABLES_IN_TEXT_SECTION
#define JUMP_TABLES_IN_TEXT_SECTION 0
#endif
#if defined(READONLY_DATA_SECTION) || defined(READONLY_DATA_SECTION_ASM_OP)
#define HAVE_READONLY_DATA_SECTION 1
#else
#define HAVE_READONLY_DATA_SECTION 0
#endif
static rtx debug_insn;
rtx current_output_insn;
static int last_linenum;
static int high_block_linenum;
static int high_function_linenum;
static const char *last_filename;
extern int length_unit_log;
rtx this_is_asm_operands;
static unsigned int insn_noperands;
static rtx last_ignored_compare = 0;
static int new_block = 1;
static int insn_counter = 0;
#ifdef HAVE_cc0
CC_STATUS cc_status;
CC_STATUS cc_prev_status;
#endif
char regs_ever_live[FIRST_PSEUDO_REGISTER];
int frame_pointer_needed;
static int block_depth;
static int app_on;
rtx final_sequence;
#ifdef ASSEMBLER_DIALECT
static int dialect_number;
#endif
static char *line_note_exists;
#ifdef HAVE_conditional_execution
rtx current_insn_predicate;
#endif
struct function_list
{
struct function_list *next;
const char *name;
long cfg_checksum;
long count_edges;
long count_calls;
};
static struct function_list *functions_head = 0;
static struct function_list **functions_tail = &functions_head;
#ifdef HAVE_ATTR_length
static int asm_insn_count PARAMS ((rtx));
#endif
static void profile_function PARAMS ((FILE *));
static void profile_after_prologue PARAMS ((FILE *));
static void notice_source_line PARAMS ((rtx));
static rtx walk_alter_subreg PARAMS ((rtx *));
static void output_asm_name PARAMS ((void));
static void output_alternate_entry_point PARAMS ((FILE *, rtx));
static tree get_mem_expr_from_op PARAMS ((rtx, int *));
static void output_asm_operand_names PARAMS ((rtx *, int *, int));
static void output_operand PARAMS ((rtx, int));
#ifdef LEAF_REGISTERS
static void leaf_renumber_regs PARAMS ((rtx));
#endif
#ifdef HAVE_cc0
static int alter_cond PARAMS ((rtx));
#endif
#ifndef ADDR_VEC_ALIGN
static int final_addr_vec_align PARAMS ((rtx));
#endif
#ifdef HAVE_ATTR_length
static int align_fuzz PARAMS ((rtx, rtx, int, unsigned));
#endif
void
init_final (filename)
const char *filename ATTRIBUTE_UNUSED;
{
app_on = 0;
final_sequence = 0;
#ifdef ASSEMBLER_DIALECT
dialect_number = ASSEMBLER_DIALECT;
#endif
}
void
end_final (filename)
const char *filename;
{
if ((profile_arc_flag || flag_create_feedback)
&& profile_info.count_instrumented_edges)
{
char name[20];
tree string_type, string_cst;
tree structure_decl, structure_value, structure_pointer_type;
tree field_decl, decl_chain, value_chain;
tree sizeof_field_value, domain_type;
string_type = build_pointer_type (char_type_node);
structure_decl = make_node (RECORD_TYPE);
structure_pointer_type = build_pointer_type (structure_decl);
decl_chain =
build_decl (FIELD_DECL, get_identifier ("zero_word"),
long_integer_type_node);
value_chain = build_tree_list (decl_chain,
convert (long_integer_type_node,
integer_zero_node));
{
char *cwd, *da_filename;
int da_filename_len;
field_decl =
build_decl (FIELD_DECL, get_identifier ("filename"), string_type);
TREE_CHAIN (field_decl) = decl_chain;
decl_chain = field_decl;
cwd = getpwd ();
da_filename_len = strlen (filename) + strlen (cwd) + 4 + 1;
da_filename = (char *) alloca (da_filename_len);
strcpy (da_filename, cwd);
strcat (da_filename, "/");
strcat (da_filename, filename);
strcat (da_filename, flag_create_feedback ? ".db" : ".da");
da_filename_len = strlen (da_filename);
string_cst = build_string (da_filename_len + 1, da_filename);
domain_type = build_index_type (build_int_2 (da_filename_len, 0));
TREE_TYPE (string_cst)
= build_array_type (char_type_node, domain_type);
value_chain = tree_cons (field_decl,
build1 (ADDR_EXPR, string_type, string_cst),
value_chain);
}
{
tree gcov_type_type = make_unsigned_type (GCOV_TYPE_SIZE);
tree gcov_type_pointer_type = build_pointer_type (gcov_type_type);
tree domain_tree
= build_index_type (build_int_2 (profile_info.count_instrumented_edges, 0));
tree gcov_type_array_type
= build_array_type (gcov_type_type, domain_tree);
tree gcov_type_array_pointer_type
= build_pointer_type (gcov_type_array_type);
tree counts_table;
field_decl =
build_decl (FIELD_DECL, get_identifier ("counts"),
gcov_type_pointer_type);
TREE_CHAIN (field_decl) = decl_chain;
decl_chain = field_decl;
if (flag_create_feedback)
counts_table = end_feedback ();
else
{
counts_table
= build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE);
TREE_STATIC (counts_table) = 1;
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
DECL_NAME (counts_table) = get_identifier (name);
assemble_variable (counts_table, 0, 0, 0);
}
value_chain = tree_cons (field_decl,
build1 (ADDR_EXPR,
gcov_type_array_pointer_type,
counts_table), value_chain);
}
field_decl
= build_decl (FIELD_DECL, get_identifier ("ncounts"),
long_integer_type_node);
TREE_CHAIN (field_decl) = decl_chain;
decl_chain = field_decl;
value_chain = tree_cons (field_decl,
convert (long_integer_type_node,
build_int_2 (profile_info.count_instrumented_edges, 0)), value_chain);
if (flag_create_feedback)
add_new_feedback_specifics_to_header (&value_chain, &decl_chain);
field_decl
= build_decl (FIELD_DECL, get_identifier ("next"),
structure_pointer_type);
TREE_CHAIN (field_decl) = decl_chain;
decl_chain = field_decl;
value_chain = tree_cons (field_decl, null_pointer_node, value_chain);
field_decl
= build_decl (FIELD_DECL, get_identifier ("sizeof_bb"),
long_integer_type_node);
TREE_CHAIN (field_decl) = decl_chain;
decl_chain = field_decl;
sizeof_field_value = tree_cons (field_decl, NULL, value_chain);
value_chain = sizeof_field_value;
{
struct function_list *item;
int num_nodes;
tree checksum_field, arc_count_field, name_field, call_count_field;
tree domain;
tree array_value_chain = NULL_TREE;
tree bb_fn_struct_type;
tree bb_fn_struct_array_type;
tree bb_fn_struct_array_pointer_type;
tree bb_fn_struct_pointer_type;
tree field_value, field_value_chain;
bb_fn_struct_type = make_node (RECORD_TYPE);
checksum_field = build_decl (FIELD_DECL, get_identifier ("checksum"),
long_integer_type_node);
arc_count_field
= build_decl (FIELD_DECL, get_identifier ("arc_count"),
integer_type_node);
TREE_CHAIN (checksum_field) = arc_count_field;
if (flag_create_feedback)
{
call_count_field
= build_decl (FIELD_DECL, get_identifier ("arc_count"),
integer_type_node);
TREE_CHAIN (arc_count_field) = call_count_field;
}
name_field
= build_decl (FIELD_DECL, get_identifier ("name"), string_type);
if (flag_create_feedback)
TREE_CHAIN (call_count_field) = name_field;
else
TREE_CHAIN (arc_count_field) = name_field;
TYPE_FIELDS (bb_fn_struct_type) = checksum_field;
num_nodes = 0;
for (item = functions_head; item != 0; item = item->next)
num_nodes++;
domain = build_index_type (build_int_2 (num_nodes, 0));
bb_fn_struct_pointer_type = build_pointer_type (bb_fn_struct_type);
bb_fn_struct_array_type
= build_array_type (bb_fn_struct_type, domain);
bb_fn_struct_array_pointer_type
= build_pointer_type (bb_fn_struct_array_type);
layout_type (bb_fn_struct_type);
layout_type (bb_fn_struct_pointer_type);
layout_type (bb_fn_struct_array_type);
layout_type (bb_fn_struct_array_pointer_type);
for (item = functions_head; item != 0; item = item->next)
{
size_t name_len;
field_value_chain
= build_tree_list (checksum_field,
convert (long_integer_type_node,
build_int_2 (item->cfg_checksum, 0)));
field_value_chain
= tree_cons (arc_count_field,
convert (integer_type_node,
build_int_2 (item->count_edges, 0)),
field_value_chain);
if (flag_create_feedback)
{
field_value_chain
= tree_cons (call_count_field,
convert (integer_type_node,
build_int_2 (item->count_calls, 0)),
field_value_chain);
}
name_len = strlen (item->name);
string_cst = build_string (name_len + 1, item->name);
domain_type = build_index_type (build_int_2 (name_len, 0));
TREE_TYPE (string_cst)
= build_array_type (char_type_node, domain_type);
field_value_chain = tree_cons (name_field,
build1 (ADDR_EXPR, string_type,
string_cst),
field_value_chain);
array_value_chain
= tree_cons (NULL_TREE, build (CONSTRUCTOR,
bb_fn_struct_type, NULL_TREE,
nreverse (field_value_chain)),
array_value_chain);
}
field_value = build_tree_list (arc_count_field,
convert (integer_type_node,
build_int_2 (-1, 0)));
array_value_chain = tree_cons (NULL_TREE,
build (CONSTRUCTOR, bb_fn_struct_type,
NULL_TREE, field_value),
array_value_chain);
field_decl
= build_decl (FIELD_DECL, get_identifier ("function_infos"),
bb_fn_struct_pointer_type);
value_chain = tree_cons (field_decl,
build1 (ADDR_EXPR,
bb_fn_struct_array_pointer_type,
build (CONSTRUCTOR,
bb_fn_struct_array_type,
NULL_TREE,
nreverse
(array_value_chain))),
value_chain);
TREE_CHAIN (field_decl) = decl_chain;
decl_chain = field_decl;
}
TYPE_FIELDS (structure_decl) = nreverse (decl_chain);
layout_type (structure_decl);
structure_value
= build (VAR_DECL, structure_decl, NULL_TREE, NULL_TREE);
DECL_INITIAL (structure_value)
= build (CONSTRUCTOR, structure_decl, NULL_TREE,
nreverse (value_chain));
TREE_STATIC (structure_value) = 1;
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
DECL_NAME (structure_value) = get_identifier (name);
TREE_VALUE (sizeof_field_value)
= convert (long_integer_type_node,
build_int_2 (int_size_in_bytes (structure_decl), 0));
assemble_variable (structure_value, 0, 0, 0);
}
}
void
default_function_pro_epilogue (file, size)
FILE *file ATTRIBUTE_UNUSED;
HOST_WIDE_INT size ATTRIBUTE_UNUSED;
{
}
void
no_asm_to_stream (file)
FILE *file ATTRIBUTE_UNUSED;
{
}
void
app_enable ()
{
if (! app_on)
{
fputs (ASM_APP_ON, asm_out_file);
app_on = 1;
}
}
void
app_disable ()
{
if (app_on)
{
fputs (ASM_APP_OFF, asm_out_file);
app_on = 0;
}
}
#ifdef DELAY_SLOTS
int
dbr_sequence_length ()
{
if (final_sequence != 0)
return XVECLEN (final_sequence, 0) - 1;
else
return 0;
}
#endif
static int *insn_lengths;
varray_type insn_addresses_;
static int insn_lengths_max_uid;
int insn_current_address;
int insn_last_address;
int insn_current_align;
struct label_alignment
{
short alignment;
short max_skip;
};
static rtx *uid_align;
static int *uid_shuid;
static struct label_alignment *label_align;
void
init_insn_lengths ()
{
if (uid_shuid)
{
free (uid_shuid);
uid_shuid = 0;
}
if (insn_lengths)
{
free (insn_lengths);
insn_lengths = 0;
insn_lengths_max_uid = 0;
}
#ifdef HAVE_ATTR_length
INSN_ADDRESSES_FREE ();
#endif
if (uid_align)
{
free (uid_align);
uid_align = 0;
}
}
int
get_attr_length (insn)
rtx insn ATTRIBUTE_UNUSED;
{
#ifdef HAVE_ATTR_length
rtx body;
int i;
int length = 0;
if (insn_lengths_max_uid > INSN_UID (insn))
return insn_lengths[INSN_UID (insn)];
else
switch (GET_CODE (insn))
{
case NOTE:
case BARRIER:
case CODE_LABEL:
return 0;
case CALL_INSN:
length = insn_default_length (insn);
break;
case JUMP_INSN:
body = PATTERN (insn);
if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
{
}
else
length = insn_default_length (insn);
break;
case INSN:
body = PATTERN (insn);
if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
return 0;
else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
length = asm_insn_count (body) * insn_default_length (insn);
else if (GET_CODE (body) == SEQUENCE)
for (i = 0; i < XVECLEN (body, 0); i++)
length += get_attr_length (XVECEXP (body, 0, i));
else
length = insn_default_length (insn);
break;
default:
break;
}
#ifdef ADJUST_INSN_LENGTH
ADJUST_INSN_LENGTH (insn, length);
#endif
return length;
#else
return 0;
#endif
}
#ifndef LABEL_ALIGN
#define LABEL_ALIGN(LABEL) align_labels_log
#endif
#ifndef LABEL_ALIGN_MAX_SKIP
#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip
#endif
#ifndef LOOP_ALIGN
#define LOOP_ALIGN(LABEL) align_loops_log
#endif
#ifndef LOOP_ALIGN_MAX_SKIP
#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip
#endif
#ifndef LABEL_ALIGN_AFTER_BARRIER
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
#endif
#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0
#endif
#ifndef JUMP_ALIGN
#define JUMP_ALIGN(LABEL) align_jumps_log
#endif
#ifndef JUMP_ALIGN_MAX_SKIP
#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip
#endif
#ifndef ADDR_VEC_ALIGN
static int
final_addr_vec_align (addr_vec)
rtx addr_vec;
{
int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)));
if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
return exact_log2 (align);
}
#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
#endif
#ifndef INSN_LENGTH_ALIGNMENT
#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log
#endif
#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)])
static int min_labelno, max_labelno;
#define LABEL_TO_ALIGNMENT(LABEL) \
(label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment)
#define LABEL_TO_MAX_SKIP(LABEL) \
(label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip)
int
label_to_alignment (label)
rtx label;
{
return LABEL_TO_ALIGNMENT (label);
}
#ifdef HAVE_ATTR_length
static int
align_fuzz (start, end, known_align_log, growth)
rtx start, end;
int known_align_log;
unsigned growth;
{
int uid = INSN_UID (start);
rtx align_label;
int known_align = 1 << known_align_log;
int end_shuid = INSN_SHUID (end);
int fuzz = 0;
for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid])
{
int align_addr, new_align;
uid = INSN_UID (align_label);
align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid];
if (uid_shuid[uid] > end_shuid)
break;
known_align_log = LABEL_TO_ALIGNMENT (align_label);
new_align = 1 << known_align_log;
if (new_align < known_align)
continue;
fuzz += (-align_addr ^ growth) & (new_align - known_align);
known_align = new_align;
}
return fuzz;
}
int
insn_current_reference_address (branch)
rtx branch;
{
rtx dest, seq;
int seq_uid;
if (! INSN_ADDRESSES_SET_P ())
return 0;
seq = NEXT_INSN (PREV_INSN (branch));
seq_uid = INSN_UID (seq);
if (GET_CODE (branch) != JUMP_INSN)
return insn_current_address;
dest = JUMP_LABEL (branch);
if (INSN_SHUID (seq) < INSN_SHUID (dest))
{
return (insn_last_address + insn_lengths[seq_uid]
- align_fuzz (seq, dest, length_unit_log, ~0));
}
else
{
return (insn_current_address
+ align_fuzz (dest, seq, length_unit_log, ~0));
}
}
#endif
void
compute_alignments ()
{
int log, max_skip, max_log;
basic_block bb;
if (label_align)
{
free (label_align);
label_align = 0;
}
max_labelno = max_label_num ();
min_labelno = get_first_label_num ();
label_align = (struct label_alignment *)
xcalloc (max_labelno - min_labelno + 1, sizeof (struct label_alignment));
if (! optimize || optimize_size)
return;
FOR_EACH_BB (bb)
{
rtx label = bb->head;
int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
edge e;
if (GET_CODE (label) != CODE_LABEL)
continue;
max_log = LABEL_ALIGN (label);
max_skip = LABEL_ALIGN_MAX_SKIP;
for (e = bb->pred; e; e = e->pred_next)
{
if (e->flags & EDGE_FALLTHRU)
has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e);
else
branch_frequency += EDGE_FREQUENCY (e);
}
if (!has_fallthru
&& (branch_frequency > BB_FREQ_MAX / 10
|| (bb->frequency > bb->prev_bb->frequency * 10
&& (bb->prev_bb->frequency
<= ENTRY_BLOCK_PTR->frequency / 2))))
{
log = JUMP_ALIGN (label);
if (max_log < log)
{
max_log = log;
max_skip = JUMP_ALIGN_MAX_SKIP;
}
}
if (has_fallthru
&& branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10
&& branch_frequency > fallthru_frequency * 2)
{
log = LOOP_ALIGN (label);
if (max_log < log)
{
max_log = log;
max_skip = LOOP_ALIGN_MAX_SKIP;
}
}
LABEL_TO_ALIGNMENT (label) = max_log;
LABEL_TO_MAX_SKIP (label) = max_skip;
}
}
#ifndef FIRST_INSN_ADDRESS
#define FIRST_INSN_ADDRESS 0
#endif
void
shorten_branches (first)
rtx first ATTRIBUTE_UNUSED;
{
rtx insn;
int max_uid;
int i;
int max_log;
int max_skip;
#ifdef HAVE_ATTR_length
#define MAX_CODE_ALIGN 16
rtx seq;
int something_changed = 1;
char *varying_length;
rtx body;
int uid;
rtx align_tab[MAX_CODE_ALIGN];
#endif
max_uid = get_max_uid ();
uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
if (max_labelno != max_label_num ())
{
int old = max_labelno;
int n_labels;
int n_old_labels;
max_labelno = max_label_num ();
n_labels = max_labelno - min_labelno + 1;
n_old_labels = old - min_labelno + 1;
label_align = (struct label_alignment *) xrealloc
(label_align, n_labels * sizeof (struct label_alignment));
if (n_old_labels > n_labels)
abort ();
memset (label_align + n_old_labels, 0,
(n_labels - n_old_labels) * sizeof (struct label_alignment));
}
max_log = 0;
max_skip = 0;
for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
{
int log;
INSN_SHUID (insn) = i++;
if (INSN_P (insn))
{
}
else if (GET_CODE (insn) == CODE_LABEL)
{
rtx next;
log = LABEL_TO_ALIGNMENT (insn);
if (max_log < log)
{
max_log = log;
max_skip = LABEL_TO_MAX_SKIP (insn);
}
log = LABEL_ALIGN (insn);
if (max_log < log)
{
max_log = log;
max_skip = LABEL_ALIGN_MAX_SKIP;
}
next = NEXT_INSN (insn);
if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
if (next && GET_CODE (next) == JUMP_INSN)
{
rtx nextbody = PATTERN (next);
if (GET_CODE (nextbody) == ADDR_VEC
|| GET_CODE (nextbody) == ADDR_DIFF_VEC)
{
log = ADDR_VEC_ALIGN (next);
if (max_log < log)
{
max_log = log;
max_skip = LABEL_ALIGN_MAX_SKIP;
}
}
}
LABEL_TO_ALIGNMENT (insn) = max_log;
LABEL_TO_MAX_SKIP (insn) = max_skip;
max_log = 0;
max_skip = 0;
}
else if (GET_CODE (insn) == BARRIER)
{
rtx label;
for (label = insn; label && ! INSN_P (label);
label = NEXT_INSN (label))
if (GET_CODE (label) == CODE_LABEL)
{
log = LABEL_ALIGN_AFTER_BARRIER (insn);
if (max_log < log)
{
max_log = log;
max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP;
}
break;
}
}
}
#ifdef HAVE_ATTR_length
insn_lengths = (int *) xmalloc (max_uid * sizeof (*insn_lengths));
insn_lengths_max_uid = max_uid;
INSN_ADDRESSES_ALLOC (max_uid);
varying_length = (char *) xcalloc (max_uid, sizeof (char));
uid_align = (rtx *) xcalloc (max_uid, sizeof *uid_align);
for (i = MAX_CODE_ALIGN; --i >= 0;)
align_tab[i] = NULL_RTX;
seq = get_last_insn ();
for (; seq; seq = PREV_INSN (seq))
{
int uid = INSN_UID (seq);
int log;
log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0);
uid_align[uid] = align_tab[0];
if (log)
{
uid_align[uid] = align_tab[log];
for (i = log - 1; i >= 0; i--)
align_tab[i] = seq;
}
}
#ifdef CASE_VECTOR_SHORTEN_MODE
if (optimize)
{
int min_shuid = INSN_SHUID (get_insns ()) - 1;
int max_shuid = INSN_SHUID (get_last_insn ()) + 1;
int rel;
for (insn = first; insn != 0; insn = NEXT_INSN (insn))
{
rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat;
int len, i, min, max, insn_shuid;
int min_align;
addr_diff_vec_flags flags;
if (GET_CODE (insn) != JUMP_INSN
|| GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
continue;
pat = PATTERN (insn);
len = XVECLEN (pat, 1);
if (len <= 0)
abort ();
min_align = MAX_CODE_ALIGN;
for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
{
rtx lab = XEXP (XVECEXP (pat, 1, i), 0);
int shuid = INSN_SHUID (lab);
if (shuid < min)
{
min = shuid;
min_lab = lab;
}
if (shuid > max)
{
max = shuid;
max_lab = lab;
}
if (min_align > LABEL_TO_ALIGNMENT (lab))
min_align = LABEL_TO_ALIGNMENT (lab);
}
XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab);
XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab);
insn_shuid = INSN_SHUID (insn);
rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
flags.min_align = min_align;
flags.base_after_vec = rel > insn_shuid;
flags.min_after_vec = min > insn_shuid;
flags.max_after_vec = max > insn_shuid;
flags.min_after_base = min > rel;
flags.max_after_base = max > rel;
ADDR_DIFF_VEC_FLAGS (pat) = flags;
}
}
#endif
for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
insn != 0;
insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
{
uid = INSN_UID (insn);
insn_lengths[uid] = 0;
if (GET_CODE (insn) == CODE_LABEL)
{
int log = LABEL_TO_ALIGNMENT (insn);
if (log)
{
int align = 1 << log;
int new_address = (insn_current_address + align - 1) & -align;
insn_lengths[uid] = new_address - insn_current_address;
}
}
INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
|| GET_CODE (insn) == CODE_LABEL)
continue;
if (INSN_DELETED_P (insn))
continue;
body = PATTERN (insn);
if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
{
if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
insn_lengths[uid] = (XVECLEN (body,
GET_CODE (body) == ADDR_DIFF_VEC)
* GET_MODE_SIZE (GET_MODE (body)));
}
else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
else if (GET_CODE (body) == SEQUENCE)
{
int i;
int const_delay_slots;
#ifdef DELAY_SLOTS
const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0));
#else
const_delay_slots = 0;
#endif
for (i = 0; i < XVECLEN (body, 0); i++)
{
rtx inner_insn = XVECEXP (body, 0, i);
int inner_uid = INSN_UID (inner_insn);
int inner_length;
if (GET_CODE (body) == ASM_INPUT
|| asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0)
inner_length = (asm_insn_count (PATTERN (inner_insn))
* insn_default_length (inner_insn));
else
inner_length = insn_default_length (inner_insn);
insn_lengths[inner_uid] = inner_length;
if (const_delay_slots)
{
if ((varying_length[inner_uid]
= insn_variable_length_p (inner_insn)) != 0)
varying_length[uid] = 1;
INSN_ADDRESSES (inner_uid) = (insn_current_address
+ insn_lengths[uid]);
}
else
varying_length[inner_uid] = 0;
insn_lengths[uid] += inner_length;
}
}
else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
{
insn_lengths[uid] = insn_default_length (insn);
varying_length[uid] = insn_variable_length_p (insn);
}
#ifdef ADJUST_INSN_LENGTH
ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
if (insn_lengths[uid] < 0)
fatal_insn ("negative insn length", insn);
#endif
}
while (something_changed)
{
something_changed = 0;
insn_current_align = MAX_CODE_ALIGN - 1;
for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
insn != 0;
insn = NEXT_INSN (insn))
{
int new_length;
#ifdef ADJUST_INSN_LENGTH
int tmp_length;
#endif
int length_align;
uid = INSN_UID (insn);
if (GET_CODE (insn) == CODE_LABEL)
{
int log = LABEL_TO_ALIGNMENT (insn);
if (log > insn_current_align)
{
int align = 1 << log;
int new_address= (insn_current_address + align - 1) & -align;
insn_lengths[uid] = new_address - insn_current_address;
insn_current_align = log;
insn_current_address = new_address;
}
else
insn_lengths[uid] = 0;
INSN_ADDRESSES (uid) = insn_current_address;
continue;
}
length_align = INSN_LENGTH_ALIGNMENT (insn);
if (length_align < insn_current_align)
insn_current_align = length_align;
insn_last_address = INSN_ADDRESSES (uid);
INSN_ADDRESSES (uid) = insn_current_address;
#ifdef CASE_VECTOR_SHORTEN_MODE
if (optimize && GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
{
rtx body = PATTERN (insn);
int old_length = insn_lengths[uid];
rtx rel_lab = XEXP (XEXP (body, 0), 0);
rtx min_lab = XEXP (XEXP (body, 2), 0);
rtx max_lab = XEXP (XEXP (body, 3), 0);
int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab));
int min_addr = INSN_ADDRESSES (INSN_UID (min_lab));
int max_addr = INSN_ADDRESSES (INSN_UID (max_lab));
rtx prev;
int rel_align = 0;
addr_diff_vec_flags flags;
flags = ADDR_DIFF_VEC_FLAGS (body);
for (prev = rel_lab;
prev
&& ! insn_lengths[INSN_UID (prev)]
&& ! (varying_length[INSN_UID (prev)] & 1);
prev = PREV_INSN (prev))
if (varying_length[INSN_UID (prev)] & 2)
{
rel_align = LABEL_TO_ALIGNMENT (prev);
break;
}
if (flags.base_after_vec)
rel_addr += insn_current_address - insn_last_address;
if (flags.min_after_vec)
min_addr += insn_current_address - insn_last_address;
if (flags.max_after_vec)
max_addr += insn_current_address - insn_last_address;
if (flags.min_after_base)
{
if (! flags.base_after_vec && flags.min_after_vec)
{
min_addr -= align_fuzz (rel_lab, insn, rel_align, 0);
min_addr -= align_fuzz (insn, min_lab, 0, 0);
}
else
min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0);
}
else
{
if (flags.base_after_vec && ! flags.min_after_vec)
{
min_addr -= align_fuzz (min_lab, insn, 0, ~0);
min_addr -= align_fuzz (insn, rel_lab, 0, ~0);
}
else
min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0);
}
if (flags.max_after_base)
{
if (! flags.base_after_vec && flags.max_after_vec)
{
max_addr += align_fuzz (rel_lab, insn, rel_align, ~0);
max_addr += align_fuzz (insn, max_lab, 0, ~0);
}
else
max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0);
}
else
{
if (flags.base_after_vec && ! flags.max_after_vec)
{
max_addr += align_fuzz (max_lab, insn, 0, 0);
max_addr += align_fuzz (insn, rel_lab, 0, 0);
}
else
max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
}
PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
max_addr - rel_addr,
body));
if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
{
insn_lengths[uid]
= (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
insn_current_address += insn_lengths[uid];
if (insn_lengths[uid] != old_length)
something_changed = 1;
}
continue;
}
#endif
if (! (varying_length[uid]))
{
if (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
{
int i;
body = PATTERN (insn);
for (i = 0; i < XVECLEN (body, 0); i++)
{
rtx inner_insn = XVECEXP (body, 0, i);
int inner_uid = INSN_UID (inner_insn);
INSN_ADDRESSES (inner_uid) = insn_current_address;
insn_current_address += insn_lengths[inner_uid];
}
}
else
insn_current_address += insn_lengths[uid];
continue;
}
if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
{
int i;
body = PATTERN (insn);
new_length = 0;
for (i = 0; i < XVECLEN (body, 0); i++)
{
rtx inner_insn = XVECEXP (body, 0, i);
int inner_uid = INSN_UID (inner_insn);
int inner_length;
INSN_ADDRESSES (inner_uid) = insn_current_address;
if (! varying_length[inner_uid])
inner_length = insn_lengths[inner_uid];
else
inner_length = insn_current_length (inner_insn);
if (inner_length != insn_lengths[inner_uid])
{
insn_lengths[inner_uid] = inner_length;
something_changed = 1;
}
insn_current_address += insn_lengths[inner_uid];
new_length += inner_length;
}
}
else
{
new_length = insn_current_length (insn);
insn_current_address += new_length;
}
#ifdef ADJUST_INSN_LENGTH
tmp_length = new_length;
ADJUST_INSN_LENGTH (insn, new_length);
insn_current_address += (new_length - tmp_length);
#endif
if (new_length != insn_lengths[uid])
{
insn_lengths[uid] = new_length;
something_changed = 1;
}
}
if (!optimize)
break;
}
free (varying_length);
#endif
}
#ifdef HAVE_ATTR_length
static int
asm_insn_count (body)
rtx body;
{
const char *template;
int count = 1;
if (GET_CODE (body) == ASM_INPUT)
template = XSTR (body, 0);
else
template = decode_asm_operands (body, NULL, NULL, NULL, NULL);
for (; *template; template++)
if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
count++;
return count;
}
#endif
void
final_start_function (first, file, optimize)
rtx first;
FILE *file;
int optimize ATTRIBUTE_UNUSED;
{
block_depth = 0;
this_is_asm_operands = 0;
#ifdef NON_SAVING_SETJMP
if (NON_SAVING_SETJMP && current_function_calls_setjmp)
{
int i;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (!call_used_regs[i])
regs_ever_live[i] = 1;
}
#endif
if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
notice_source_line (first);
high_block_linenum = high_function_linenum = last_linenum;
(*debug_hooks->begin_prologue) (last_linenum, last_filename);
#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO)
if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
dwarf2out_begin_prologue (0, NULL);
#endif
#ifdef LEAF_REG_REMAP
if (current_function_uses_only_leaf_regs)
leaf_renumber_regs (first);
#endif
#ifdef PROFILE_BEFORE_PROLOGUE
if (current_function_profile)
profile_function (file);
#endif
#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
if (dwarf2out_do_frame ())
dwarf2out_frame_debug (NULL_RTX);
#endif
if (write_symbols)
{
remove_unnecessary_notes ();
scope_to_insns_finalize ();
number_blocks (current_function_decl);
TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
}
(*targetm.asm_out.function_prologue) (file, get_frame_size ());
#ifdef HAVE_prologue
if (! HAVE_prologue)
#endif
profile_after_prologue (file);
}
static void
profile_after_prologue (file)
FILE *file ATTRIBUTE_UNUSED;
{
#ifndef PROFILE_BEFORE_PROLOGUE
if (current_function_profile)
profile_function (file);
#endif
}
static void
profile_function (file)
FILE *file ATTRIBUTE_UNUSED;
{
#ifndef NO_PROFILE_COUNTERS
int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
#endif
#if defined(ASM_OUTPUT_REG_PUSH)
#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM)
int sval = current_function_returns_struct;
#endif
#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
int cxt = current_function_needs_context;
#endif
#endif
#ifndef NO_PROFILE_COUNTERS
data_section ();
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
ASM_OUTPUT_INTERNAL_LABEL (file, "LP", current_function_funcdef_no);
assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
#endif
function_section (current_function_decl);
#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (sval)
ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM);
#else
#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (sval)
{
ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM);
}
#endif
#endif
#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (cxt)
ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
#else
#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (cxt)
{
ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
}
#endif
#endif
FUNCTION_PROFILER (file, current_function_funcdef_no);
#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (cxt)
ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
#else
#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (cxt)
{
ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
}
#endif
#endif
#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (sval)
ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM);
#else
#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (sval)
{
ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM);
}
#endif
#endif
}
void
final_end_function ()
{
app_disable ();
(*debug_hooks->end_function) (high_function_linenum);
(*targetm.asm_out.function_epilogue) (asm_out_file, get_frame_size ());
#ifdef OUTPUT_COMPILER_STUB
output_compiler_stub ();
#endif
(*debug_hooks->end_epilogue) (last_linenum, last_filename);
#if defined (DWARF2_UNWIND_INFO)
if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
&& dwarf2out_do_frame ())
dwarf2out_end_epilogue (last_linenum, last_filename);
#endif
}
void
final (first, file, optimize, prescan)
rtx first;
FILE *file;
int optimize;
int prescan;
{
rtx insn;
int max_line = 0;
int max_uid = 0;
last_ignored_compare = 0;
new_block = 1;
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG)
{
rtx last = 0;
for (insn = first; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
{
if ((RTX_INTEGRATED_P (insn)
&& strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0)
|| (last != 0
&& NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
&& NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
{
delete_insn (insn);
continue;
}
last = insn;
if (NOTE_LINE_NUMBER (insn) > max_line)
max_line = NOTE_LINE_NUMBER (insn);
}
}
else
#endif
{
for (insn = first; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line)
max_line = NOTE_LINE_NUMBER (insn);
}
line_note_exists = (char *) xcalloc (max_line + 1, sizeof (char));
for (insn = first; insn; insn = NEXT_INSN (insn))
{
if (INSN_UID (insn) > max_uid)
max_uid = INSN_UID (insn);
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
line_note_exists[NOTE_LINE_NUMBER (insn)] = 1;
#ifdef HAVE_cc0
if (optimize && GET_CODE (insn) == JUMP_INSN)
{
rtx lab = JUMP_LABEL (insn);
if (lab && LABEL_NUSES (lab) == 1)
{
LABEL_REFS (lab) = insn;
}
}
#endif
}
init_recog ();
CC_STATUS_INIT;
for (insn = NEXT_INSN (first); insn;)
{
#ifdef HAVE_ATTR_length
if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
{
if (GET_CODE (insn) == NOTE)
insn_current_address = -1;
else
abort ();
}
else
insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
#endif
insn = final_scan_insn (insn, file, optimize, prescan, 0);
}
if (cfun->arc_profile || flag_create_feedback)
{
struct function_list *new_item = xmalloc (sizeof (struct function_list));
*functions_tail = new_item;
functions_tail = &new_item->next;
new_item->next = 0;
new_item->name = xstrdup (IDENTIFIER_POINTER
(DECL_ASSEMBLER_NAME (current_function_decl)));
new_item->cfg_checksum = profile_info.current_function_cfg_checksum;
new_item->count_edges = profile_info.count_edges_instrumented_now;
new_item->count_calls = profile_info.count_calls_instrumented_now;
}
free (line_note_exists);
line_note_exists = NULL;
}
const char *
get_insn_template (code, insn)
int code;
rtx insn;
{
const void *output = insn_data[code].output;
switch (insn_data[code].output_format)
{
case INSN_OUTPUT_FORMAT_SINGLE:
return (const char *) output;
case INSN_OUTPUT_FORMAT_MULTI:
return ((const char *const *) output)[which_alternative];
case INSN_OUTPUT_FORMAT_FUNCTION:
if (insn == NULL)
abort ();
return (*(insn_output_fn) output) (recog_data.operand, insn);
default:
abort ();
}
}
static void
output_alternate_entry_point (file, insn)
FILE *file;
rtx insn;
{
const char *name = LABEL_NAME (insn);
switch (LABEL_KIND (insn))
{
case LABEL_WEAK_ENTRY:
#ifdef ASM_WEAKEN_LABEL
ASM_WEAKEN_LABEL (file, name);
#endif
case LABEL_GLOBAL_ENTRY:
(*targetm.asm_out.globalize_label) (file, name);
case LABEL_STATIC_ENTRY:
#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
#endif
ASM_OUTPUT_LABEL (file, name);
break;
case LABEL_NORMAL:
default:
abort ();
}
}
bool
scan_ahead_for_unlikely_executed_note (insn)
rtx insn;
{
rtx temp;
for (temp = insn; temp; temp = NEXT_INSN (temp))
{
if ((GET_CODE (temp) == NOTE)
&& (NOTE_LINE_NUMBER (temp) == NOTE_INSN_UNLIKELY_EXECUTED_CODE))
return true;
if (INSN_P (temp))
return false;
}
return false;
}
static bool
is_jump_table_basic_block (insn)
rtx insn;
{
rtx next;
if (GET_CODE (insn) == CODE_LABEL)
{
next = NEXT_INSN (insn);
if (next
&& (GET_CODE (next) == JUMP_INSN)
&& ((GET_CODE (PATTERN (next)) == ADDR_VEC)
|| (GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC)))
return true;
}
return false;
}
rtx
final_scan_insn (insn, file, optimize, prescan, nopeepholes)
rtx insn;
FILE *file;
int optimize ATTRIBUTE_UNUSED;
int prescan;
int nopeepholes ATTRIBUTE_UNUSED;
{
#ifdef HAVE_cc0
rtx set;
#endif
insn_counter++;
if (INSN_DELETED_P (insn))
return NEXT_INSN (insn);
switch (GET_CODE (insn))
{
case NOTE:
if (prescan > 0)
break;
switch (NOTE_LINE_NUMBER (insn))
{
case NOTE_INSN_DELETED:
case NOTE_INSN_LOOP_BEG:
case NOTE_INSN_LOOP_END:
case NOTE_INSN_LOOP_END_TOP_COND:
case NOTE_INSN_LOOP_CONT:
case NOTE_INSN_LOOP_VTOP:
case NOTE_INSN_FUNCTION_END:
case NOTE_INSN_REPEATED_LINE_NUMBER:
case NOTE_INSN_EXPECTED_VALUE:
case NOTE_INSN_DONT_SHORTEN_BRANCH:
case NOTE_INSN_FDO_COUNT_INCOMING:
case NOTE_INSN_FDO_COUNT_OUTGOING:
case NOTE_INSN_FDO_COUNT_TABLEJUMP:
case NOTE_INSN_FDO_COUNT_BLOCK:
break;
case NOTE_INSN_UNLIKELY_EXECUTED_CODE:
if (!(in_unlikely_text_section ()))
unlikely_text_section ();
break;
case NOTE_INSN_BASIC_BLOCK:
if (in_unlikely_text_section ())
if (!(scan_ahead_for_unlikely_executed_note (insn)))
text_section ();
#ifdef IA64_UNWIND_INFO
IA64_UNWIND_EMIT (asm_out_file, insn);
#endif
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s basic block %d\n",
ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index);
break;
case NOTE_INSN_EH_REGION_BEG:
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB",
NOTE_EH_HANDLER (insn));
break;
case NOTE_INSN_EH_REGION_END:
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE",
NOTE_EH_HANDLER (insn));
break;
case NOTE_INSN_PROLOGUE_END:
(*targetm.asm_out.function_end_prologue) (file);
profile_after_prologue (file);
break;
case NOTE_INSN_EPILOGUE_BEG:
(*targetm.asm_out.function_begin_epilogue) (file);
break;
case NOTE_INSN_FUNCTION_BEG:
app_disable ();
(*debug_hooks->end_prologue) (last_linenum, last_filename);
break;
case NOTE_INSN_BLOCK_BEG:
if (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
|| write_symbols == DWARF_DEBUG
|| write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG
|| write_symbols == VMS_DEBUG)
{
int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
app_disable ();
++block_depth;
high_block_linenum = last_linenum;
(*debug_hooks->begin_block) (last_linenum, n);
TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
}
break;
case NOTE_INSN_BLOCK_END:
if (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
|| write_symbols == DWARF_DEBUG
|| write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG
|| write_symbols == VMS_DEBUG)
{
int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
app_disable ();
--block_depth;
if (block_depth < 0)
abort ();
(*debug_hooks->end_block) (high_block_linenum, n);
}
break;
case NOTE_INSN_DELETED_LABEL:
ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
break;
case 0:
break;
default:
if (NOTE_LINE_NUMBER (insn) <= 0)
abort ();
{
rtx note;
int note_after = 0;
for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note))
{
if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL)
break;
else if (GET_CODE (note) == NOTE
&& (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG
|| NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END
|| NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG))
break;
else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0)
{
int num;
for (num = NOTE_LINE_NUMBER (insn) + 1;
num < NOTE_LINE_NUMBER (note);
num++)
if (line_note_exists[num])
break;
if (num >= NOTE_LINE_NUMBER (note))
note_after = 1;
break;
}
}
if (!note_after)
{
notice_source_line (insn);
(*debug_hooks->source_line) (last_linenum, last_filename);
}
}
break;
}
break;
case BARRIER:
#if defined (DWARF2_UNWIND_INFO)
if (dwarf2out_do_frame ())
dwarf2out_frame_debug (insn);
#endif
break;
case CODE_LABEL:
if (CODE_LABEL_NUMBER (insn) <= max_labelno)
{
int align = LABEL_TO_ALIGNMENT (insn);
#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
int max_skip = LABEL_TO_MAX_SKIP (insn);
#endif
if (align && NEXT_INSN (insn))
{
#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
#else
#ifdef ASM_OUTPUT_ALIGN_WITH_NOP
ASM_OUTPUT_ALIGN_WITH_NOP (file, align);
#else
ASM_OUTPUT_ALIGN (file, align);
#endif
#endif
}
}
#ifdef HAVE_cc0
CC_STATUS_INIT;
if (0 )
{
rtx jump = LABEL_REFS (insn);
rtx barrier = prev_nonnote_insn (insn);
rtx prev;
if (barrier && GET_CODE (barrier) == BARRIER
&& jump && GET_CODE (jump) == JUMP_INSN
&& (prev = prev_nonnote_insn (jump))
&& GET_CODE (prev) == INSN)
{
NOTICE_UPDATE_CC (PATTERN (prev), prev);
NOTICE_UPDATE_CC (PATTERN (jump), jump);
}
}
#endif
if (prescan > 0)
break;
new_block = 1;
#ifdef FINAL_PRESCAN_LABEL
FINAL_PRESCAN_INSN (insn, NULL, 0);
#endif
if (LABEL_NAME (insn))
(*debug_hooks->label) (insn);
if (is_jump_table_basic_block(insn))
{
}
else if (scan_ahead_for_unlikely_executed_note (insn))
{
if (!(in_unlikely_text_section ()))
unlikely_text_section ();
}
else
{
if (in_unlikely_text_section ())
text_section ();
}
if (app_on)
{
fputs (ASM_APP_OFF, file);
app_on = 0;
}
if (NEXT_INSN (insn) != 0
&& GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
{
rtx nextbody = PATTERN (NEXT_INSN (insn));
if (GET_CODE (nextbody) == ADDR_VEC
|| GET_CODE (nextbody) == ADDR_DIFF_VEC)
{
#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
#else
if (! JUMP_TABLES_IN_TEXT_SECTION)
{
int log_align;
readonly_data_section ();
#ifdef ADDR_VEC_ALIGN
log_align = ADDR_VEC_ALIGN (NEXT_INSN (insn));
#else
log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
#endif
ASM_OUTPUT_ALIGN (file, log_align);
}
else
function_section (current_function_decl);
#ifdef ASM_OUTPUT_CASE_LABEL
ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
NEXT_INSN (insn));
#else
ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
#endif
#endif
break;
}
}
if (LABEL_ALT_ENTRY_P (insn))
output_alternate_entry_point (file, insn);
else
ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
break;
default:
{
rtx body = PATTERN (insn);
int insn_code_number;
const char *template;
rtx note;
if (GET_CODE (body) == USE
|| GET_CODE (body) == CLOBBER)
break;
#ifdef HAVE_cc0
note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
if (note)
{
NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
cc_prev_status = cc_status;
}
#endif
if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
{
#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC))
int vlen, idx;
#endif
if (prescan > 0)
break;
if (app_on)
{
fputs (ASM_APP_OFF, file);
app_on = 0;
}
#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
if (GET_CODE (body) == ADDR_VEC)
{
#ifdef ASM_OUTPUT_ADDR_VEC
ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
#else
abort ();
#endif
}
else
{
#ifdef ASM_OUTPUT_ADDR_DIFF_VEC
ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
#else
abort ();
#endif
}
#else
vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC);
for (idx = 0; idx < vlen; idx++)
{
if (GET_CODE (body) == ADDR_VEC)
{
#ifdef ASM_OUTPUT_ADDR_VEC_ELT
ASM_OUTPUT_ADDR_VEC_ELT
(file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
#else
abort ();
#endif
}
else
{
#ifdef ASM_OUTPUT_ADDR_DIFF_ELT
ASM_OUTPUT_ADDR_DIFF_ELT
(file,
body,
CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
#else
abort ();
#endif
}
}
#ifdef ASM_OUTPUT_CASE_END
ASM_OUTPUT_CASE_END (file,
CODE_LABEL_NUMBER (PREV_INSN (insn)),
insn);
#endif
#endif
function_section (current_function_decl);
break;
}
if (GET_CODE (body) == ASM_INPUT)
{
const char *string = XSTR (body, 0);
CC_STATUS_INIT;
if (prescan > 0)
break;
if (string[0])
{
if (! app_on)
{
fputs (ASM_APP_ON, file);
app_on = 1;
}
fprintf (asm_out_file, "\t%s\n", string);
}
break;
}
if (asm_noperands (body) >= 0)
{
unsigned int noperands = asm_noperands (body);
rtx *ops = (rtx *) alloca (noperands * sizeof (rtx));
const char *string;
CC_STATUS_INIT;
if (prescan > 0)
break;
string = decode_asm_operands (body, ops, NULL, NULL, NULL);
insn_noperands = noperands;
this_is_asm_operands = insn;
if (string[0])
{
if (! app_on)
{
fputs (ASM_APP_ON, file);
app_on = 1;
}
output_asm_insn (string, ops);
}
this_is_asm_operands = 0;
break;
}
if (prescan <= 0 && app_on)
{
fputs (ASM_APP_OFF, file);
app_on = 0;
}
if (GET_CODE (body) == SEQUENCE)
{
int i;
rtx next;
if (prescan > 0)
break;
final_sequence = body;
next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1);
if (next != XVECEXP (body, 0, 1))
{
final_sequence = 0;
return next;
}
for (i = 1; i < XVECLEN (body, 0); i++)
{
rtx insn = XVECEXP (body, 0, i);
rtx next = NEXT_INSN (insn);
do
insn = final_scan_insn (insn, file, 0, prescan, 1);
while (insn != next);
}
#ifdef DBR_OUTPUT_SEQEND
DBR_OUTPUT_SEQEND (file);
#endif
final_sequence = 0;
if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
{
CC_STATUS_INIT;
}
break;
}
body = PATTERN (insn);
#ifdef HAVE_cc0
set = single_set (insn);
if (optimize)
{
#if 0
rtx set = single_set (insn);
#endif
if (set
&& GET_CODE (SET_DEST (set)) == CC0
&& insn != last_ignored_compare)
{
if (GET_CODE (SET_SRC (set)) == SUBREG)
SET_SRC (set) = alter_subreg (&SET_SRC (set));
else if (GET_CODE (SET_SRC (set)) == COMPARE)
{
if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
XEXP (SET_SRC (set), 0)
= alter_subreg (&XEXP (SET_SRC (set), 0));
if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
XEXP (SET_SRC (set), 1)
= alter_subreg (&XEXP (SET_SRC (set), 1));
}
if ((cc_status.value1 != 0
&& rtx_equal_p (SET_SRC (set), cc_status.value1))
|| (cc_status.value2 != 0
&& rtx_equal_p (SET_SRC (set), cc_status.value2)))
{
if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
&& ! volatile_refs_p (PATTERN (insn)))
{
last_ignored_compare = insn;
break;
}
}
}
}
#endif
#ifndef STACK_REGS
if (final_sequence == 0
&& prescan >= 0
&& GET_CODE (insn) == INSN && GET_CODE (body) == SET
&& GET_CODE (SET_SRC (body)) == REG
&& GET_CODE (SET_DEST (body)) == REG
&& REGNO (SET_SRC (body)) == REGNO (SET_DEST (body)))
break;
#endif
#ifdef HAVE_cc0
if (cc_status.flags != 0
&& GET_CODE (insn) == JUMP_INSN
&& GET_CODE (body) == SET
&& SET_DEST (body) == pc_rtx
&& GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
&& GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<'
&& XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx
&& prescan >= 0)
{
int result = alter_cond (XEXP (SET_SRC (body), 0));
if (result == 1)
SET_SRC (body) = XEXP (SET_SRC (body), 1);
if (result == -1)
SET_SRC (body) = XEXP (SET_SRC (body), 2);
if (SET_SRC (body) == pc_rtx)
{
delete_insn (insn);
break;
}
else if (GET_CODE (SET_SRC (body)) == RETURN)
PATTERN (insn) = body = SET_SRC (body);
if (result != 0)
INSN_CODE (insn) = -1;
}
if (cc_status.flags != 0
&& set != 0)
{
rtx cond_rtx, then_rtx, else_rtx;
if (GET_CODE (insn) != JUMP_INSN
&& GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
{
cond_rtx = XEXP (SET_SRC (set), 0);
then_rtx = XEXP (SET_SRC (set), 1);
else_rtx = XEXP (SET_SRC (set), 2);
}
else
{
cond_rtx = SET_SRC (set);
then_rtx = const_true_rtx;
else_rtx = const0_rtx;
}
switch (GET_CODE (cond_rtx))
{
case GTU:
case GT:
case LTU:
case LT:
case GEU:
case GE:
case LEU:
case LE:
case EQ:
case NE:
{
int result;
if (XEXP (cond_rtx, 0) != cc0_rtx)
break;
result = alter_cond (cond_rtx);
if (result == 1)
validate_change (insn, &SET_SRC (set), then_rtx, 0);
else if (result == -1)
validate_change (insn, &SET_SRC (set), else_rtx, 0);
else if (result == 2)
INSN_CODE (insn) = -1;
if (SET_DEST (set) == SET_SRC (set))
delete_insn (insn);
}
break;
default:
break;
}
}
#endif
#ifdef HAVE_peephole
if (optimize && !flag_no_peephole && !nopeepholes)
{
rtx next = peephole (insn);
if (next != 0 && next != NEXT_INSN (insn))
{
rtx prev = PREV_INSN (insn);
for (note = NEXT_INSN (insn); note != next;
note = NEXT_INSN (note))
final_scan_insn (note, file, optimize, prescan, nopeepholes);
note = NEXT_INSN (insn);
PREV_INSN (note) = prev;
NEXT_INSN (prev) = note;
NEXT_INSN (PREV_INSN (next)) = insn;
PREV_INSN (insn) = PREV_INSN (next);
NEXT_INSN (insn) = next;
PREV_INSN (next) = insn;
}
body = PATTERN (insn);
}
#endif
insn_code_number = recog_memoized (insn);
cleanup_subreg_operands (insn);
if (flag_dump_rtl_in_asm)
{
print_rtx_head = ASM_COMMENT_START;
print_rtl_single (asm_out_file, insn);
print_rtx_head = "";
}
if (! constrain_operands_cached (1))
fatal_insn_not_found (insn);
#ifdef FINAL_PRESCAN_INSN
FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
#endif
#ifdef HAVE_conditional_execution
if (GET_CODE (PATTERN (insn)) == COND_EXEC)
current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
else
current_insn_predicate = NULL_RTX;
#endif
#ifdef HAVE_cc0
cc_prev_status = cc_status;
NOTICE_UPDATE_CC (body, insn);
#endif
current_output_insn = debug_insn = insn;
#if defined (DWARF2_UNWIND_INFO)
if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ())
dwarf2out_frame_debug (insn);
#endif
template = get_insn_template (insn_code_number, insn);
if (template == 0)
{
rtx prev;
if (prev_nonnote_insn (insn) != last_ignored_compare)
abort ();
new_block = 0;
for (prev = insn;
prev != last_ignored_compare;
prev = PREV_INSN (prev))
{
if (GET_CODE (prev) == NOTE)
delete_insn (prev);
}
return prev;
}
if (template[0] == '#' && template[1] == '\0')
{
rtx new = try_split (body, insn, 0);
if (new == insn && PATTERN (new) == body)
fatal_insn ("could not split insn", insn);
#ifdef HAVE_ATTR_length
abort ();
#endif
new_block = 0;
return new;
}
if (prescan > 0)
break;
#ifdef IA64_UNWIND_INFO
IA64_UNWIND_EMIT (asm_out_file, insn);
#endif
output_asm_insn (template, recog_data.operand);
#if defined (DWARF2_UNWIND_INFO)
#if defined (HAVE_prologue)
if (GET_CODE (insn) == INSN && dwarf2out_do_frame ())
dwarf2out_frame_debug (insn);
#else
if (!ACCUMULATE_OUTGOING_ARGS
&& GET_CODE (insn) == INSN
&& dwarf2out_do_frame ())
dwarf2out_frame_debug (insn);
#endif
#endif
#if 0
INSN_DELETED_P (insn) = 1;
#endif
note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX);
if (note)
assemble_vtable_entry (XEXP (XEXP (note, 0), 0),
INTVAL (XEXP (XEXP (note, 0), 1)));
current_output_insn = debug_insn = 0;
}
}
return NEXT_INSN (insn);
}
static void
notice_source_line (insn)
rtx insn;
{
const char *filename = NOTE_SOURCE_FILE (insn);
last_filename = filename;
last_linenum = NOTE_LINE_NUMBER (insn);
high_block_linenum = MAX (last_linenum, high_block_linenum);
high_function_linenum = MAX (last_linenum, high_function_linenum);
}
void
cleanup_subreg_operands (insn)
rtx insn;
{
int i;
extract_insn_cached (insn);
for (i = 0; i < recog_data.n_operands; i++)
{
if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]);
else if (GET_CODE (recog_data.operand[i]) == PLUS
|| GET_CODE (recog_data.operand[i]) == MULT
|| GET_CODE (recog_data.operand[i]) == MEM)
recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]);
}
for (i = 0; i < recog_data.n_dups; i++)
{
if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG)
*recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]);
else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
|| GET_CODE (*recog_data.dup_loc[i]) == MULT
|| GET_CODE (*recog_data.dup_loc[i]) == MEM)
*recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]);
}
}
rtx
alter_subreg (xp)
rtx *xp;
{
rtx x = *xp;
rtx y = SUBREG_REG (x);
if (GET_CODE (y) == MEM)
*xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x));
else
{
rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
SUBREG_BYTE (x));
if (new != 0)
*xp = new;
else if (GET_CODE (y) == REG)
{
unsigned int regno = subreg_hard_regno (x, 1);
PUT_CODE (x, REG);
REGNO (x) = regno;
ORIGINAL_REGNO (x) = ORIGINAL_REGNO (y);
RTX_FLAG (x, used) = 0;
}
else
abort ();
}
return *xp;
}
static rtx
walk_alter_subreg (xp)
rtx *xp;
{
rtx x = *xp;
switch (GET_CODE (x))
{
case PLUS:
case MULT:
XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1));
break;
case MEM:
XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
break;
case SUBREG:
return alter_subreg (xp);
default:
break;
}
return *xp;
}
#ifdef HAVE_cc0
static int
alter_cond (cond)
rtx cond;
{
int value = 0;
if (cc_status.flags & CC_REVERSED)
{
value = 2;
PUT_CODE (cond, swap_condition (GET_CODE (cond)));
}
if (cc_status.flags & CC_INVERTED)
{
value = 2;
PUT_CODE (cond, reverse_condition (GET_CODE (cond)));
}
if (cc_status.flags & CC_NOT_POSITIVE)
switch (GET_CODE (cond))
{
case LE:
case LEU:
case GEU:
return 1;
case GT:
case GTU:
case LTU:
return -1;
case GE:
PUT_CODE (cond, EQ);
value = 2;
break;
case LT:
PUT_CODE (cond, NE);
value = 2;
break;
default:
break;
}
if (cc_status.flags & CC_NOT_NEGATIVE)
switch (GET_CODE (cond))
{
case GE:
case GEU:
return 1;
case LT:
case LTU:
return -1;
case LE:
case LEU:
PUT_CODE (cond, EQ);
value = 2;
break;
case GT:
case GTU:
PUT_CODE (cond, NE);
value = 2;
break;
default:
break;
}
if (cc_status.flags & CC_NO_OVERFLOW)
switch (GET_CODE (cond))
{
case GEU:
return 1;
case LEU:
PUT_CODE (cond, EQ);
value = 2;
break;
case GTU:
PUT_CODE (cond, NE);
value = 2;
break;
case LTU:
return -1;
default:
break;
}
if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
switch (GET_CODE (cond))
{
default:
abort ();
case NE:
PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
value = 2;
break;
case EQ:
PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
value = 2;
break;
}
if (cc_status.flags & CC_NOT_SIGNED)
switch (GET_CODE (cond))
{
case LE:
PUT_CODE (cond, LEU);
value = 2;
break;
case LT:
PUT_CODE (cond, LTU);
value = 2;
break;
case GT:
PUT_CODE (cond, GTU);
value = 2;
break;
case GE:
PUT_CODE (cond, GEU);
value = 2;
break;
default:
break;
}
return value;
}
#endif
void
output_operand_lossage VPARAMS ((const char *msgid, ...))
{
char *fmt_string;
char *new_message;
const char *pfx_str;
VA_OPEN (ap, msgid);
VA_FIXEDARG (ap, const char *, msgid);
pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: ";
asprintf (&fmt_string, "%s%s", pfx_str, _(msgid));
vasprintf (&new_message, fmt_string, ap);
if (this_is_asm_operands)
error_for_asm (this_is_asm_operands, "%s", new_message);
else
internal_error ("%s", new_message);
free (fmt_string);
free (new_message);
VA_CLOSE (ap);
}
static void
output_asm_name ()
{
if (debug_insn)
{
int num = INSN_CODE (debug_insn);
fprintf (asm_out_file, "\t%s %d\t%s",
ASM_COMMENT_START, INSN_UID (debug_insn),
insn_data[num].name);
if (insn_data[num].n_alternatives > 1)
fprintf (asm_out_file, "/%d", which_alternative + 1);
#ifdef HAVE_ATTR_length
fprintf (asm_out_file, "\t[length = %d]",
get_attr_length (debug_insn));
#endif
debug_insn = 0;
}
}
static tree
get_mem_expr_from_op (op, paddressp)
rtx op;
int *paddressp;
{
tree expr;
int inner_addressp;
*paddressp = 0;
if (op == NULL)
return 0;
if (GET_CODE (op) == REG && ORIGINAL_REGNO (op) >= FIRST_PSEUDO_REGISTER)
return REGNO_DECL (ORIGINAL_REGNO (op));
else if (GET_CODE (op) != MEM)
return 0;
if (MEM_EXPR (op) != 0)
return MEM_EXPR (op);
*paddressp = 1;
op = XEXP (op, 0);
if ((expr = get_mem_expr_from_op (op, &inner_addressp)) && ! inner_addressp)
return expr;
else if (GET_CODE (op) == PLUS
&& (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
return expr;
while (GET_RTX_CLASS (GET_CODE (op)) == '1'
|| GET_RTX_CLASS (GET_CODE (op)) == '2')
op = XEXP (op, 0);
expr = get_mem_expr_from_op (op, &inner_addressp);
return inner_addressp ? 0 : expr;
}
static void
output_asm_operand_names (operands, oporder, nops)
rtx *operands;
int *oporder;
int nops;
{
int wrote = 0;
int i;
for (i = 0; i < nops; i++)
{
int addressp;
tree expr = get_mem_expr_from_op (operands[oporder[i]], &addressp);
if (expr)
{
fprintf (asm_out_file, "%c%s %s",
wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START,
addressp ? "*" : "");
print_mem_expr (asm_out_file, expr);
wrote = 1;
}
}
}
void
output_asm_insn (template, operands)
const char *template;
rtx *operands;
{
const char *p;
int c;
#ifdef ASSEMBLER_DIALECT
int dialect = 0;
#endif
int oporder[MAX_RECOG_OPERANDS];
char opoutput[MAX_RECOG_OPERANDS];
int ops = 0;
if (*template == 0)
return;
memset (opoutput, 0, sizeof opoutput);
p = template;
putc ('\t', asm_out_file);
#ifdef ASM_OUTPUT_OPCODE
ASM_OUTPUT_OPCODE (asm_out_file, p);
#endif
while ((c = *p++))
switch (c)
{
case '\n':
if (flag_verbose_asm)
output_asm_operand_names (operands, oporder, ops);
if (flag_print_asm_name)
output_asm_name ();
ops = 0;
memset (opoutput, 0, sizeof opoutput);
putc (c, asm_out_file);
#ifdef ASM_OUTPUT_OPCODE
while ((c = *p) == '\t')
{
putc (c, asm_out_file);
p++;
}
ASM_OUTPUT_OPCODE (asm_out_file, p);
#endif
break;
#ifdef ASSEMBLER_DIALECT
case '{':
{
int i;
if (dialect)
output_operand_lossage ("nested assembly dialect alternatives");
else
dialect = 1;
for (i = 0; i < dialect_number; i++)
{
while (*p && *p != '}' && *p++ != '|')
;
if (*p == '}')
break;
if (*p == '|')
p++;
}
if (*p == '\0')
output_operand_lossage ("unterminated assembly dialect alternative");
}
break;
case '|':
if (dialect)
{
do
{
if (*p == '\0')
{
output_operand_lossage ("unterminated assembly dialect alternative");
break;
}
}
while (*p++ != '}');
dialect = 0;
}
else
putc (c, asm_out_file);
break;
case '}':
if (! dialect)
putc (c, asm_out_file);
dialect = 0;
break;
#endif
case '%':
if (*p == '%')
{
p++;
putc (c, asm_out_file);
}
else if (*p == '=')
{
p++;
fprintf (asm_out_file, "%d", insn_counter);
}
else if (ISALPHA (*p))
{
int letter = *p++;
c = atoi (p);
if (! ISDIGIT (*p))
output_operand_lossage ("operand number missing after %%-letter");
else if (this_is_asm_operands
&& (c < 0 || (unsigned int) c >= insn_noperands))
output_operand_lossage ("operand number out of range");
else if (letter == 'l')
output_asm_label (operands[c]);
else if (letter == 'a')
output_address (operands[c]);
else if (letter == 'c')
{
if (CONSTANT_ADDRESS_P (operands[c]))
output_addr_const (asm_out_file, operands[c]);
else
output_operand (operands[c], 'c');
}
else if (letter == 'n')
{
if (GET_CODE (operands[c]) == CONST_INT)
fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
- INTVAL (operands[c]));
else
{
putc ('-', asm_out_file);
output_addr_const (asm_out_file, operands[c]);
}
}
else
output_operand (operands[c], letter);
if (!opoutput[c])
oporder[ops++] = c;
opoutput[c] = 1;
while (ISDIGIT (c = *p))
p++;
}
else if (ISDIGIT (*p))
{
c = atoi (p);
if (this_is_asm_operands
&& (c < 0 || (unsigned int) c >= insn_noperands))
output_operand_lossage ("operand number out of range");
else
output_operand (operands[c], 0);
if (!opoutput[c])
oporder[ops++] = c;
opoutput[c] = 1;
while (ISDIGIT (c = *p))
p++;
}
#ifdef PRINT_OPERAND_PUNCT_VALID_P
else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p))
output_operand (NULL_RTX, *p++);
#endif
else
output_operand_lossage ("invalid %%-code");
break;
default:
putc (c, asm_out_file);
}
if (flag_verbose_asm)
output_asm_operand_names (operands, oporder, ops);
if (flag_print_asm_name)
output_asm_name ();
putc ('\n', asm_out_file);
}
void
output_asm_label (x)
rtx x;
{
char buf[256];
if (GET_CODE (x) == LABEL_REF)
x = XEXP (x, 0);
if (GET_CODE (x) == CODE_LABEL
|| (GET_CODE (x) == NOTE
&& NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL))
ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
else
output_operand_lossage ("`%%l' operand isn't a label");
assemble_name (asm_out_file, buf);
}
static void
output_operand (x, code)
rtx x;
int code ATTRIBUTE_UNUSED;
{
if (x && GET_CODE (x) == SUBREG)
x = alter_subreg (&x);
if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
abort ();
PRINT_OPERAND (asm_out_file, x, code);
}
void
output_address (x)
rtx x;
{
walk_alter_subreg (&x);
PRINT_OPERAND_ADDRESS (asm_out_file, x);
}
void
output_addr_const (file, x)
FILE *file;
rtx x;
{
char buf[256];
restart:
switch (GET_CODE (x))
{
case PC:
putc ('.', file);
break;
case SYMBOL_REF:
#ifdef ASM_OUTPUT_SYMBOL_REF
ASM_OUTPUT_SYMBOL_REF (file, x);
#else
assemble_name (file, XSTR (x, 0));
#endif
break;
case LABEL_REF:
x = XEXP (x, 0);
case CODE_LABEL:
ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
#ifdef ASM_OUTPUT_LABEL_REF
ASM_OUTPUT_LABEL_REF (file, buf);
#else
assemble_name (file, buf);
#endif
break;
case CONST_INT:
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
break;
case CONST:
output_addr_const (file, XEXP (x, 0));
break;
case CONST_DOUBLE:
if (GET_MODE (x) == VOIDmode)
{
if (CONST_DOUBLE_HIGH (x))
fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
else if (CONST_DOUBLE_LOW (x) < 0)
fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
else
fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
}
else
output_operand_lossage ("floating constant misused");
break;
case PLUS:
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
{
output_addr_const (file, XEXP (x, 1));
if (INTVAL (XEXP (x, 0)) >= 0)
fprintf (file, "+");
output_addr_const (file, XEXP (x, 0));
}
else
{
output_addr_const (file, XEXP (x, 0));
if (GET_CODE (XEXP (x, 1)) != CONST_INT
|| INTVAL (XEXP (x, 1)) >= 0)
fprintf (file, "+");
output_addr_const (file, XEXP (x, 1));
}
break;
case MINUS:
x = simplify_subtraction (x);
if (GET_CODE (x) != MINUS)
goto restart;
output_addr_const (file, XEXP (x, 0));
fprintf (file, "-");
if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0)
|| GET_CODE (XEXP (x, 1)) == PC
|| GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
output_addr_const (file, XEXP (x, 1));
else
{
fputs (targetm.asm_out.open_paren, file);
output_addr_const (file, XEXP (x, 1));
fputs (targetm.asm_out.close_paren, file);
}
break;
case ZERO_EXTEND:
case SIGN_EXTEND:
case SUBREG:
output_addr_const (file, XEXP (x, 0));
break;
default:
#ifdef OUTPUT_ADDR_CONST_EXTRA
OUTPUT_ADDR_CONST_EXTRA (file, x, fail);
break;
fail:
#endif
output_operand_lossage ("invalid expression as operand");
}
}
void
asm_fprintf VPARAMS ((FILE *file, const char *p, ...))
{
char buf[10];
char *q, c;
VA_OPEN (argptr, p);
VA_FIXEDARG (argptr, FILE *, file);
VA_FIXEDARG (argptr, const char *, p);
buf[0] = '%';
while ((c = *p++))
switch (c)
{
#ifdef ASSEMBLER_DIALECT
case '{':
{
int i;
for (i = 0; i < dialect_number; i++)
{
while (*p && *p++ != '|')
;
if (*p == '|')
p++;
}
}
break;
case '|':
while (*p && *p++ != '}')
;
break;
case '}':
break;
#endif
case '%':
c = *p++;
q = &buf[1];
while (ISDIGIT (c) || c == '.')
{
*q++ = c;
c = *p++;
}
switch (c)
{
case '%':
fprintf (file, "%%");
break;
case 'd': case 'i': case 'u':
case 'x': case 'p': case 'X':
case 'o':
*q++ = c;
*q = 0;
fprintf (file, buf, va_arg (argptr, int));
break;
case 'w':
#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
#else
#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
*q++ = 'l';
#else
*q++ = 'l';
*q++ = 'l';
#endif
#endif
*q++ = *p++;
*q = 0;
fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
break;
case 'l':
*q++ = c;
*q++ = *p++;
*q = 0;
fprintf (file, buf, va_arg (argptr, long));
break;
case 'e':
case 'f':
case 'g':
*q++ = c;
*q = 0;
fprintf (file, buf, va_arg (argptr, double));
break;
case 's':
*q++ = c;
*q = 0;
fprintf (file, buf, va_arg (argptr, char *));
break;
case 'O':
#ifdef ASM_OUTPUT_OPCODE
ASM_OUTPUT_OPCODE (asm_out_file, p);
#endif
break;
case 'R':
#ifdef REGISTER_PREFIX
fprintf (file, "%s", REGISTER_PREFIX);
#endif
break;
case 'I':
#ifdef IMMEDIATE_PREFIX
fprintf (file, "%s", IMMEDIATE_PREFIX);
#endif
break;
case 'L':
#ifdef LOCAL_LABEL_PREFIX
fprintf (file, "%s", LOCAL_LABEL_PREFIX);
#endif
break;
case 'U':
fputs (user_label_prefix, file);
break;
#ifdef ASM_FPRINTF_EXTENSIONS
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'J': case 'K':
case 'M': case 'N': case 'P': case 'Q': case 'S':
case 'T': case 'V': case 'W': case 'Y': case 'Z':
break;
ASM_FPRINTF_EXTENSIONS (file, argptr, p)
#endif
default:
abort ();
}
break;
default:
fputc (c, file);
}
VA_CLOSE (argptr);
}
void
split_double (value, first, second)
rtx value;
rtx *first, *second;
{
if (GET_CODE (value) == CONST_INT)
{
if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
{
unsigned HOST_WIDE_INT low, high;
unsigned HOST_WIDE_INT mask, sign_bit, sign_extend;
sign_bit = 1;
sign_bit <<= BITS_PER_WORD - 1;
mask = sign_bit << 1;
mask--;
sign_extend = ~mask;
low = INTVAL (value);
low &= mask;
if (low & sign_bit)
low |= sign_extend;
high = INTVAL (value);
high >>= BITS_PER_WORD - 1;
high >>= 1;
high &= mask;
if (high & sign_bit)
high |= sign_extend;
if (WORDS_BIG_ENDIAN)
{
*first = GEN_INT (high);
*second = GEN_INT (low);
}
else
{
*first = GEN_INT (low);
*second = GEN_INT (high);
}
}
else
{
rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx);
if (WORDS_BIG_ENDIAN)
{
*first = high;
*second = value;
}
else
{
*first = value;
*second = high;
}
}
}
else if (GET_CODE (value) != CONST_DOUBLE)
{
if (WORDS_BIG_ENDIAN)
{
*first = const0_rtx;
*second = value;
}
else
{
*first = value;
*second = const0_rtx;
}
}
else if (GET_MODE (value) == VOIDmode
|| GET_MODE_CLASS (GET_MODE (value)) == MODE_INT)
{
if (WORDS_BIG_ENDIAN)
{
*first = GEN_INT (CONST_DOUBLE_HIGH (value));
*second = GEN_INT (CONST_DOUBLE_LOW (value));
}
else
{
*first = GEN_INT (CONST_DOUBLE_LOW (value));
*second = GEN_INT (CONST_DOUBLE_HIGH (value));
}
}
else
{
REAL_VALUE_TYPE r;
long l[2];
REAL_VALUE_FROM_CONST_DOUBLE (r, value);
REAL_VALUE_TO_TARGET_DOUBLE (r, l);
#if HOST_BITS_PER_LONG > 32
if (BITS_PER_WORD < HOST_BITS_PER_LONG && BITS_PER_WORD == 32)
{
if (l[0] & ((long) 1 << 31))
l[0] |= ((long) (-1) << 32);
if (l[1] & ((long) 1 << 31))
l[1] |= ((long) (-1) << 32);
}
#endif
*first = GEN_INT ((HOST_WIDE_INT) l[0]);
*second = GEN_INT ((HOST_WIDE_INT) l[1]);
}
}
int
leaf_function_p ()
{
rtx insn;
rtx link;
if (current_function_profile || profile_arc_flag)
return 0;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == CALL_INSN
&& ! SIBLING_CALL_P (insn))
return 0;
if (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SEQUENCE
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
&& ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
return 0;
}
for (link = current_function_epilogue_delay_list;
link;
link = XEXP (link, 1))
{
insn = XEXP (link, 0);
if (GET_CODE (insn) == CALL_INSN
&& ! SIBLING_CALL_P (insn))
return 0;
if (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SEQUENCE
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
&& ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
return 0;
}
return 1;
}
int
final_forward_branch_p (insn)
rtx insn;
{
int insn_id, label_id;
if (!uid_shuid)
abort ();
insn_id = INSN_SHUID (insn);
label_id = INSN_SHUID (JUMP_LABEL (insn));
if (!insn_id || !label_id)
abort ();
return insn_id < label_id;
}
#ifdef LEAF_REGISTERS
int
only_leaf_regs_used ()
{
int i;
char *permitted_reg_in_leaf_functions = LEAF_REGISTERS;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if ((regs_ever_live[i] || global_regs[i])
&& ! permitted_reg_in_leaf_functions[i])
return 0;
if (current_function_uses_pic_offset_table
&& pic_offset_table_rtx != 0
&& GET_CODE (pic_offset_table_rtx) == REG
&& ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
return 0;
return 1;
}
static void
leaf_renumber_regs (first)
rtx first;
{
rtx insn;
for (insn = first; insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
leaf_renumber_regs_insn (PATTERN (insn));
for (insn = current_function_epilogue_delay_list;
insn;
insn = XEXP (insn, 1))
if (INSN_P (XEXP (insn, 0)))
leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0)));
}
void
leaf_renumber_regs_insn (in_rtx)
rtx in_rtx;
{
int i, j;
const char *format_ptr;
if (in_rtx == 0)
return;
if (GET_CODE (in_rtx) == REG)
{
int newreg;
if (in_rtx->used)
return;
newreg = REGNO (in_rtx);
if (newreg >= FIRST_PSEUDO_REGISTER)
{
in_rtx->used = 1;
return;
}
newreg = LEAF_REG_REMAP (newreg);
if (newreg < 0)
abort ();
regs_ever_live[REGNO (in_rtx)] = 0;
regs_ever_live[newreg] = 1;
REGNO (in_rtx) = newreg;
in_rtx->used = 1;
}
if (INSN_P (in_rtx))
{
leaf_renumber_regs_insn (PATTERN (in_rtx));
return;
}
format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
switch (*format_ptr++)
{
case 'e':
leaf_renumber_regs_insn (XEXP (in_rtx, i));
break;
case 'E':
if (NULL != XVEC (in_rtx, i))
{
for (j = 0; j < XVECLEN (in_rtx, i); j++)
leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
}
break;
case 'S':
case 's':
case '0':
case 'i':
case 'w':
case 'n':
case 'u':
break;
default:
abort ();
}
}
#endif