#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.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 "cfglayout.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#endif
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
#include "dwarf2out.h"
#endif
#ifdef DBX_DEBUGGING_INFO
#include "dbxout.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
#define SEEN_BB 1
#define SEEN_NOTE 2
#define SEEN_EMITTED 4
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 insn_counter = 0;
#ifdef HAVE_cc0
CC_STATUS cc_status;
CC_STATUS cc_prev_status;
#endif
char regs_ever_live[FIRST_PSEUDO_REGISTER];
char regs_asm_clobbered[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
#ifdef HAVE_conditional_execution
rtx current_insn_predicate;
#endif
#ifdef HAVE_ATTR_length
static int asm_insn_count (rtx);
#endif
static void profile_function (FILE *);
static void profile_after_prologue (FILE *);
static bool notice_source_line (rtx);
static rtx walk_alter_subreg (rtx *);
static void output_asm_name (void);
static void output_alternate_entry_point (FILE *, rtx);
static tree get_mem_expr_from_op (rtx, int *);
static void output_asm_operand_names (rtx *, int *, int);
static void output_operand (rtx, int);
static void calculate_alignments (void);
#ifdef LEAF_REGISTERS
static void leaf_renumber_regs (rtx);
#endif
#ifdef HAVE_cc0
static int alter_cond (rtx);
#endif
#ifndef ADDR_VEC_ALIGN
static int final_addr_vec_align (rtx);
#endif
#ifdef HAVE_ATTR_length
static int align_fuzz (rtx, rtx, int, unsigned);
#endif
void
init_final (const char *filename ATTRIBUTE_UNUSED)
{
app_on = 0;
final_sequence = 0;
#ifdef ASSEMBLER_DIALECT
dialect_number = ASSEMBLER_DIALECT;
#endif
}
void
default_function_pro_epilogue (FILE *file ATTRIBUTE_UNUSED,
HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
}
void
no_asm_to_stream (FILE *file ATTRIBUTE_UNUSED)
{
}
void
app_enable (void)
{
if (! app_on)
{
fputs (ASM_APP_ON, asm_out_file);
app_on = 1;
}
}
void
app_disable (void)
{
if (app_on)
{
fputs (ASM_APP_OFF, asm_out_file);
app_on = 0;
}
}
#ifdef DELAY_SLOTS
int
dbr_sequence_length (void)
{
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 (void)
{
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 (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 (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 (rtx label)
{
return LABEL_TO_ALIGNMENT (label);
}
int
label_to_max_skip (rtx label)
{
return LABEL_TO_MAX_SKIP (label);
}
#ifdef HAVE_ATTR_length
static int
align_fuzz (rtx start, rtx end, int known_align_log, unsigned int 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 (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 (!JUMP_P (branch))
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 (void)
{
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 = xcalloc (max_labelno - min_labelno + 1,
sizeof (struct label_alignment));
#if !defined (TARGET_ARM)
if (! optimize || optimize_size)
return;
#endif
FOR_EACH_BB (bb)
{
rtx label = BB_HEAD (bb);
int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
edge e;
edge_iterator ei;
if (!LABEL_P (label)
#if !defined (TARGET_ARM)
|| probably_never_executed_bb_p (bb)
#endif
)
continue;
max_log = LABEL_ALIGN (label);
max_skip = LABEL_ALIGN_MAX_SKIP;
FOR_EACH_EDGE (e, ei, bb->preds)
{
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
&& maybe_hot_bb_p (bb)
&& 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;
}
}
void
shorten_branches (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
int something_changed = 1;
char *varying_length;
rtx body;
int uid;
bool asms_present = false;
#endif
max_uid = get_max_uid ();
free (uid_shuid);
uid_shuid = 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 = xrealloc (label_align,
n_labels * sizeof (struct label_alignment));
gcc_assert (n_old_labels <= n_labels);
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 (LABEL_P (insn))
{
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_nonnote_insn (insn);
if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
if (next && JUMP_P (next))
{
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 (BARRIER_P (insn))
{
rtx label;
for (label = insn; label && ! INSN_P (label);
label = NEXT_INSN (label))
if (LABEL_P (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 = xmalloc (max_uid * sizeof (*insn_lengths));
insn_lengths_max_uid = max_uid;
INSN_ADDRESSES_ALLOC (max_uid);
varying_length = xcalloc (max_uid, sizeof (char));
uid_align = xcalloc (max_uid, sizeof *uid_align);
calculate_alignments ();
#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 (!JUMP_P (insn)
|| GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
continue;
pat = PATTERN (insn);
len = XVECLEN (pat, 1);
gcc_assert (len > 0);
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));
memset (&flags, 0, sizeof (flags));
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
insn_current_address = 0;
#ifdef TARGET_ARM
if (TARGET_THUMB)
insn_current_address = count_thumb_unexpanded_prologue ();
#endif
for (insn = first;
insn != 0;
insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
{
uid = INSN_UID (insn);
insn_lengths[uid] = 0;
if (LABEL_P (insn))
{
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 (NOTE_P (insn) || BARRIER_P (insn)
|| LABEL_P (insn))
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);
asms_present = true;
}
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;
insn_current_address = 0;
#ifdef TARGET_ARM
if (TARGET_THUMB)
insn_current_address = count_thumb_unexpanded_prologue ();
#endif
for (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 (LABEL_P (insn))
{
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 && JUMP_P (insn)
#ifdef TARGET_ARM
&& !asms_present
#endif
&& 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)));
#ifdef TARGET_ARM
#ifdef ADJUST_INSN_LENGTH
ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
#endif
#endif
insn_current_address += insn_lengths[uid];
#ifdef TARGET_ARM
LABEL_TO_ALIGNMENT (rel_lab) = ADDR_VEC_ALIGN (insn);
calculate_alignments ();
#endif
if (insn_lengths[uid] != old_length)
something_changed = 1;
}
continue;
}
#endif
if (! (varying_length[uid]))
{
if (NONJUMP_INSN_P (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 (NONJUMP_INSN_P (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
}
static void
calculate_alignments (void)
{
int i;
rtx seq;
rtx align_tab[MAX_CODE_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 = (LABEL_P (seq) ? 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 HAVE_ATTR_length
static int
asm_insn_count (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 (rtx first ATTRIBUTE_UNUSED, FILE *file,
int optimizing ATTRIBUTE_UNUSED)
{
block_depth = 0;
this_is_asm_operands = 0;
last_filename = locator_file (prologue_locator);
last_linenum = locator_line (prologue_locator);
high_block_linenum = high_function_linenum = last_linenum;
if (!flag_save_repository || !flag_pch_file)
(*debug_hooks->begin_prologue) (last_linenum, last_filename);
#if defined (DWARF2_UNWIND_INFO) || defined (TARGET_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, false);
#endif
if (write_symbols)
{
remove_unnecessary_notes ();
reemit_insn_block_notes ();
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 ATTRIBUTE_UNUSED)
{
#ifndef PROFILE_BEFORE_PROLOGUE
if (current_function_profile)
profile_function (file);
#endif
}
static void
profile_function (FILE *file ATTRIBUTE_UNUSED)
{
#ifndef NO_PROFILE_COUNTERS
# define NO_PROFILE_COUNTERS 0
#endif
#if defined(ASM_OUTPUT_REG_PUSH)
int sval = current_function_returns_struct;
rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1);
#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
int cxt = cfun->static_chain_decl != NULL;
#endif
#endif
if (! NO_PROFILE_COUNTERS)
{
int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
data_section ();
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no);
assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
}
function_section (current_function_decl);
#if defined(ASM_OUTPUT_REG_PUSH)
if (sval && svrtx != NULL_RTX && REG_P (svrtx))
ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
#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(ASM_OUTPUT_REG_PUSH)
if (sval && svrtx != NULL_RTX && REG_P (svrtx))
ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
#endif
}
void
final_end_function (void)
{
app_disable ();
(*debug_hooks->end_function) (high_function_linenum);
targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ());
(*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 (rtx first, FILE *file, int optimizing, int prescan)
{
rtx insn;
int max_uid = 0;
int seen = 0;
last_ignored_compare = 0;
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG)
{
rtx last = 0;
for (insn = first; insn; insn = NEXT_INSN (insn))
if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0)
{
if (last != 0
#ifdef USE_MAPPED_LOCATION
&& NOTE_SOURCE_LOCATION (insn) == NOTE_SOURCE_LOCATION (last)
#else
&& NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
&& NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)
#endif
)
{
delete_insn (insn);
continue;
}
last = insn;
}
}
#endif
for (insn = first; insn; insn = NEXT_INSN (insn))
{
if (INSN_UID (insn) > max_uid)
max_uid = INSN_UID (insn);
#ifdef HAVE_cc0
if (optimizing && JUMP_P (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 ())
{
gcc_assert (NOTE_P (insn));
insn_current_address = -1;
}
else
insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
#endif
insn = final_scan_insn (insn, file, optimizing, prescan, 0, &seen);
}
}
const char *
get_insn_template (int code, rtx insn)
{
switch (insn_data[code].output_format)
{
case INSN_OUTPUT_FORMAT_SINGLE:
return insn_data[code].output.single;
case INSN_OUTPUT_FORMAT_MULTI:
return insn_data[code].output.multi[which_alternative];
case INSN_OUTPUT_FORMAT_FUNCTION:
gcc_assert (insn);
return (*insn_data[code].output.function) (recog_data.operand, insn);
default:
gcc_unreachable ();
}
}
static void
output_alternate_entry_point (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:
gcc_unreachable ();
}
}
bool
scan_ahead_for_unlikely_executed_note (rtx insn)
{
rtx temp;
int bb_note_count = 0;
for (temp = insn; temp; temp = NEXT_INSN (temp))
{
if (NOTE_P (temp)
&& NOTE_LINE_NUMBER (temp) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
return true;
if (NOTE_P (temp)
&& NOTE_LINE_NUMBER (temp) == NOTE_INSN_BASIC_BLOCK)
{
bb_note_count++;
if (bb_note_count > 1)
return false;
}
if (INSN_P (temp))
return false;
}
return false;
}
rtx
final_scan_insn (rtx insn, FILE *file, int optimizing ATTRIBUTE_UNUSED,
int prescan, int nopeepholes ATTRIBUTE_UNUSED,
int *seen)
{
#ifdef HAVE_cc0
rtx set;
#endif
rtx next;
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_FUNCTION_END:
case NOTE_INSN_REPEATED_LINE_NUMBER:
case NOTE_INSN_EXPECTED_VALUE:
case NOTE_INSN_ALLOCA:
break;
case NOTE_INSN_UNLIKELY_EXECUTED_CODE:
unlikely_text_section ();
break;
case NOTE_INSN_BASIC_BLOCK:
if (flag_reorder_blocks_and_partition
&& !scan_ahead_for_unlikely_executed_note (insn))
function_section (current_function_decl);
#ifdef TARGET_UNWIND_INFO
targetm.asm_out.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);
if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB)
{
*seen |= SEEN_EMITTED;
last_filename = NULL;
}
else
*seen |= SEEN_BB;
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);
if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
{
*seen |= SEEN_EMITTED;
last_filename = NULL;
}
else
*seen |= SEEN_NOTE;
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);
if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
{
*seen |= SEEN_EMITTED;
last_filename = NULL;
}
else
*seen |= SEEN_NOTE;
break;
case NOTE_INSN_BLOCK_BEG:
if (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
|| 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;
if (!flag_save_repository || !flag_pch_file)
(*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 == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG
|| write_symbols == VMS_DEBUG)
{
int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
app_disable ();
--block_depth;
gcc_assert (block_depth >= 0);
if (!flag_save_repository || !flag_pch_file)
(*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 NOTE_INSN_VAR_LOCATION:
(*debug_hooks->var_location) (insn);
break;
case 0:
break;
default:
gcc_assert (NOTE_LINE_NUMBER (insn) > 0);
break;
}
break;
case BARRIER:
#if defined (DWARF2_UNWIND_INFO)
if (dwarf2out_do_frame ())
dwarf2out_frame_debug (insn, false);
#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 && BARRIER_P (barrier)
&& jump && JUMP_P (jump)
&& (prev = prev_nonnote_insn (jump))
&& NONJUMP_INSN_P (prev))
{
NOTICE_UPDATE_CC (PATTERN (prev), prev);
NOTICE_UPDATE_CC (PATTERN (jump), jump);
}
}
#endif
if (prescan > 0)
break;
if (LABEL_NAME (insn))
(*debug_hooks->label) (insn);
if (flag_reorder_blocks_and_partition
&& targetm.have_named_sections)
{
rtx tmp_table, tmp_label;
if (LABEL_P (insn)
&& tablejump_p (NEXT_INSN (insn), &tmp_label, &tmp_table))
{
}
else if (scan_ahead_for_unlikely_executed_note (insn))
unlikely_text_section ();
else if (in_unlikely_text_section ())
function_section (current_function_decl);
}
if (app_on)
{
fputs (ASM_APP_OFF, file);
app_on = 0;
}
next = next_nonnote_insn (insn);
if (next != 0 && JUMP_P (next))
{
rtx nextbody = PATTERN (next);
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;
targetm.asm_out.function_rodata_section (current_function_decl);
#ifdef ADDR_VEC_ALIGN
log_align = ADDR_VEC_ALIGN (next);
#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);
#else
targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
#endif
#endif
break;
}
}
if (LABEL_ALT_ENTRY_P (insn))
output_alternate_entry_point (file, insn);
else
targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
break;
default:
{
rtx body = PATTERN (insn);
int insn_code_number;
const char *template;
if (GET_CODE (body) == USE
|| GET_CODE (body) == CLOBBER)
break;
#ifdef HAVE_cc0
{
rtx 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 (! JUMP_TABLES_IN_TEXT_SECTION)
targetm.asm_out.function_rodata_section (current_function_decl);
else
function_section (current_function_decl);
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
gcc_unreachable ();
#endif
}
else
{
#ifdef ASM_OUTPUT_ADDR_DIFF_VEC
ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
#else
gcc_unreachable ();
#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
gcc_unreachable ();
#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
gcc_unreachable ();
#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 (notice_source_line (insn))
{
if (!flag_save_repository || !flag_pch_file)
(*debug_hooks->source_line) (last_linenum, last_filename);
}
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 = 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;
#ifdef FINAL_PRESCAN_INSN
FINAL_PRESCAN_INSN (insn, ops, insn_noperands);
#endif
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;
if (prescan > 0)
break;
final_sequence = body;
#if defined (DWARF2_UNWIND_INFO)
if (dwarf2out_do_frame ())
for (i = 1; i < XVECLEN (body, 0); i++)
dwarf2out_frame_debug (XVECEXP (body, 0, i), false);
#endif
next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1, seen);
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, seen);
while (insn != next);
}
#ifdef DBR_OUTPUT_SEQEND
DBR_OUTPUT_SEQEND (file);
#endif
final_sequence = 0;
if (CALL_P (XVECEXP (body, 0, 0)))
{
CC_STATUS_INIT;
}
break;
}
body = PATTERN (insn);
#ifdef HAVE_cc0
set = single_set (insn);
if (optimizing)
{
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
&& NONJUMP_INSN_P (insn) && GET_CODE (body) == SET
&& REG_P (SET_SRC (body))
&& REG_P (SET_DEST (body))
&& REGNO (SET_SRC (body)) == REGNO (SET_DEST (body)))
break;
#endif
#ifdef HAVE_cc0
if (cc_status.flags != 0
&& JUMP_P (insn)
&& GET_CODE (body) == SET
&& SET_DEST (body) == pc_rtx
&& GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
&& COMPARISON_P (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 (!JUMP_P (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 (optimizing && !flag_no_peephole && !nopeepholes)
{
rtx next = peephole (insn);
if (next != 0 && next != NEXT_INSN (insn))
{
rtx note, prev = PREV_INSN (insn);
for (note = NEXT_INSN (insn); note != next;
note = NEXT_INSN (note))
final_scan_insn (note, file, optimizing, prescan, nopeepholes, seen);
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 (CALL_P (insn) && dwarf2out_do_frame ())
dwarf2out_frame_debug (insn, false);
#endif
template = get_insn_template (insn_code_number, insn);
if (template == 0)
{
rtx prev;
gcc_assert (prev_nonnote_insn (insn) == last_ignored_compare);
for (prev = insn;
prev != last_ignored_compare;
prev = PREV_INSN (prev))
{
if (NOTE_P (prev))
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
gcc_unreachable ();
#endif
return new;
}
if (prescan > 0)
break;
#ifdef TARGET_UNWIND_INFO
targetm.asm_out.unwind_emit (asm_out_file, insn);
#endif
output_asm_insn (template, recog_data.operand);
#if defined (DWARF2_UNWIND_INFO)
if (final_sequence == 0
#if !defined (HAVE_prologue)
&& !ACCUMULATE_OUTGOING_ARGS
#endif
&& dwarf2out_do_frame ())
dwarf2out_frame_debug (insn, true);
#endif
current_output_insn = debug_insn = 0;
}
}
return NEXT_INSN (insn);
}
static bool
notice_source_line (rtx insn)
{
const char *filename = insn_file (insn);
int linenum = insn_line (insn);
if (filename && (filename != last_filename || last_linenum != linenum))
{
last_filename = filename;
last_linenum = linenum;
high_block_linenum = MAX (last_linenum, high_block_linenum);
high_function_linenum = MAX (last_linenum, high_function_linenum);
return true;
}
return false;
}
void
cleanup_subreg_operands (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
|| MEM_P (recog_data.operand[i]))
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
|| MEM_P (*recog_data.dup_loc[i]))
*recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]);
}
}
rtx
alter_subreg (rtx *xp)
{
rtx x = *xp;
rtx y = SUBREG_REG (x);
if (MEM_P (y))
{
int offset = SUBREG_BYTE (x);
if (offset == 0
&& GET_MODE_SIZE (GET_MODE (y)) < GET_MODE_SIZE (GET_MODE (x)))
{
int difference = GET_MODE_SIZE (GET_MODE (y))
- GET_MODE_SIZE (GET_MODE (x));
if (WORDS_BIG_ENDIAN)
offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
if (BYTES_BIG_ENDIAN)
offset += difference % UNITS_PER_WORD;
}
*xp = adjust_address (y, GET_MODE (x), offset);
}
else
{
rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
SUBREG_BYTE (x));
if (new != 0)
*xp = new;
else if (REG_P (y))
{
unsigned int regno = subreg_regno (x);
*xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x));
}
}
return *xp;
}
static rtx
walk_alter_subreg (rtx *xp)
{
rtx x = *xp;
switch (GET_CODE (x))
{
case PLUS:
case MULT:
case AND:
XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1));
break;
case MEM:
case ZERO_EXTEND:
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 (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:
gcc_unreachable ();
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 (const char *cmsgid, ...)
{
char *fmt_string;
char *new_message;
const char *pfx_str;
va_list ap;
va_start (ap, cmsgid);
pfx_str = this_is_asm_operands ? _("invalid 'asm': ") : "output_operand: ";
asprintf (&fmt_string, "%s%s", pfx_str, _(cmsgid));
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_end (ap);
}
static void
output_asm_name (void)
{
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 (rtx op, int *paddressp)
{
tree expr;
int inner_addressp;
*paddressp = 0;
if (REG_P (op))
return REG_EXPR (op);
else if (!MEM_P (op))
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)) == RTX_UNARY
|| GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH)
op = XEXP (op, 0);
expr = get_mem_expr_from_op (op, &inner_addressp);
return inner_addressp ? 0 : expr;
}
static void
output_asm_operand_names (rtx *operands, int *oporder, int nops)
{
int wrote = 0;
int i;
for (i = 0; i < nops; i++)
{
int addressp;
rtx op = operands[oporder[i]];
tree expr = get_mem_expr_from_op (op, &addressp);
fprintf (asm_out_file, "%c%s",
wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START);
wrote = 1;
if (expr)
{
fprintf (asm_out_file, "%s",
addressp ? "*" : "");
print_mem_expr (asm_out_file, expr);
wrote = 1;
}
else if (REG_P (op) && ORIGINAL_REGNO (op)
&& ORIGINAL_REGNO (op) != REGNO (op))
fprintf (asm_out_file, " tmp%i", ORIGINAL_REGNO (op));
}
}
void
output_asm_insn (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++;
unsigned long opnum;
char *endptr;
opnum = strtoul (p, &endptr, 10);
if (endptr == p)
output_operand_lossage ("operand number missing "
"after %%-letter");
else if (this_is_asm_operands && opnum >= insn_noperands)
output_operand_lossage ("operand number out of range");
else if (letter == 'l')
output_asm_label (operands[opnum]);
else if (letter == 'a')
output_address (operands[opnum]);
else if (letter == 'c')
{
if (CONSTANT_ADDRESS_P (operands[opnum]))
output_addr_const (asm_out_file, operands[opnum]);
else
output_operand (operands[opnum], 'c');
}
else if (letter == 'n')
{
if (GET_CODE (operands[opnum]) == CONST_INT)
fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
- INTVAL (operands[opnum]));
else
{
putc ('-', asm_out_file);
output_addr_const (asm_out_file, operands[opnum]);
}
}
else
output_operand (operands[opnum], letter);
if (!opoutput[opnum])
oporder[ops++] = opnum;
opoutput[opnum] = 1;
p = endptr;
c = *p;
}
else if (ISDIGIT (*p))
{
unsigned long opnum;
char *endptr;
opnum = strtoul (p, &endptr, 10);
if (this_is_asm_operands && opnum >= insn_noperands)
output_operand_lossage ("operand number out of range");
else
output_operand (operands[opnum], 0);
if (!opoutput[opnum])
oporder[ops++] = opnum;
opoutput[opnum] = 1;
p = endptr;
c = *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 (rtx x)
{
char buf[256];
if (GET_CODE (x) == LABEL_REF)
x = XEXP (x, 0);
if (LABEL_P (x)
|| (NOTE_P (x)
&& 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 (rtx x, int code ATTRIBUTE_UNUSED)
{
if (x && GET_CODE (x) == SUBREG)
x = alter_subreg (&x);
gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
PRINT_OPERAND (asm_out_file, x, code);
}
void
output_address (rtx x)
{
walk_alter_subreg (&x);
PRINT_OPERAND_ADDRESS (asm_out_file, x);
}
void
output_addr_const (FILE *file, rtx x)
{
char buf[256];
restart:
switch (GET_CODE (x))
{
case PC:
putc ('.', file);
break;
case SYMBOL_REF:
if (SYMBOL_REF_DECL (x))
mark_decl_referenced (SYMBOL_REF_DECL (x));
#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 (FILE *file, const char *p, ...)
{
char buf[10];
char *q, c;
va_list argptr;
va_start (argptr, 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 (strchr ("-+ #0", c))
{
*q++ = c;
c = *p++;
}
while (ISDIGIT (c) || c == '.')
{
*q++ = c;
c = *p++;
}
switch (c)
{
case '%':
putc ('%', file);
break;
case 'd': case 'i': case 'u':
case 'x': case 'X': case 'o':
case 'c':
*q++ = c;
*q = 0;
fprintf (file, buf, va_arg (argptr, int));
break;
case 'w':
memcpy (q, HOST_WIDE_INT_PRINT, strlen (HOST_WIDE_INT_PRINT));
q += strlen (HOST_WIDE_INT_PRINT);
*q++ = *p++;
*q = 0;
fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
break;
case 'l':
*q++ = c;
#ifdef HAVE_LONG_LONG
if (*p == 'l')
{
*q++ = *p++;
*q++ = *p++;
*q = 0;
fprintf (file, buf, va_arg (argptr, long long));
}
else
#endif
{
*q++ = *p++;
*q = 0;
fprintf (file, buf, va_arg (argptr, long));
}
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:
gcc_unreachable ();
}
break;
default:
putc (c, file);
}
va_end (argptr);
}
void
split_double (rtx value, rtx *first, rtx *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 (l[0]);
*second = GEN_INT (l[1]);
}
}
int
leaf_function_p (void)
{
rtx insn;
rtx link;
if (current_function_profile || profile_arc_flag)
return 0;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (CALL_P (insn)
&& ! SIBLING_CALL_P (insn))
return 0;
if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE
&& CALL_P (XVECEXP (PATTERN (insn), 0, 0))
&& ! 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 (CALL_P (insn)
&& ! SIBLING_CALL_P (insn))
return 0;
if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE
&& CALL_P (XVECEXP (PATTERN (insn), 0, 0))
&& ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
return 0;
}
return 1;
}
int
final_forward_branch_p (rtx insn)
{
int insn_id, label_id;
gcc_assert (uid_shuid);
insn_id = INSN_SHUID (insn);
label_id = INSN_SHUID (JUMP_LABEL (insn));
gcc_assert (insn_id && label_id);
return insn_id < label_id;
}
#ifdef LEAF_REGISTERS
int
only_leaf_regs_used (void)
{
int i;
const char *const 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
&& REG_P (pic_offset_table_rtx)
&& ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
return 0;
return 1;
}
static void
leaf_renumber_regs (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 (rtx in_rtx)
{
int i, j;
const char *format_ptr;
if (in_rtx == 0)
return;
if (REG_P (in_rtx))
{
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);
gcc_assert (newreg >= 0);
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:
gcc_unreachable ();
}
}
#endif
int debug_nesting = 0;
static tree *symbol_queue;
int symbol_queue_index = 0;
static int symbol_queue_size = 0;
void
debug_flush_symbol_queue (void)
{
int i;
++debug_nesting;
for (i = 0; i < symbol_queue_index; ++i)
{
int saved_tree_used = TREE_USED (symbol_queue[i]);
int saved_suppress_debug = TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]);
TREE_USED (symbol_queue[i]) = 1;
TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = 0;
#ifdef DBX_DEBUGGING_INFO
dbxout_symbol (symbol_queue[i], 0);
#endif
TREE_USED (symbol_queue[i]) = saved_tree_used;
TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = saved_suppress_debug;
}
symbol_queue_index = 0;
#ifdef DBX_DEBUGGING_INFO
dbxout_flush_type_queue ();
#endif
--debug_nesting;
}
void
debug_queue_symbol (tree decl)
{
if (symbol_queue_index >= symbol_queue_size)
{
symbol_queue_size += 10;
symbol_queue = xrealloc (symbol_queue,
symbol_queue_size * sizeof (tree));
}
symbol_queue[symbol_queue_index++] = decl;
}
void
debug_free_queue (void)
{
if (symbol_queue)
{
free (symbol_queue);
symbol_queue = NULL;
symbol_queue_size = 0;
}
}