#include "config.h"
#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "regs.h"
#include "insn-config.h"
#include "insn-flags.h"
#include "insn-attr.h"
#include "insn-codes.h"
#include "recog.h"
#include "conditions.h"
#include "flags.h"
#include "real.h"
#include "hard-reg-set.h"
#include "defaults.h"
#include "output.h"
#include "except.h"
#include "toplev.h"
#include "reload.h"
#include "intl.h"
#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
#include "dbxout.h"
#if defined (USG) || !defined (HAVE_STAB_H)
#include "gstab.h"
#else
#include <stab.h>
#endif
#endif
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#endif
#ifdef DWARF_DEBUGGING_INFO
#include "dwarfout.h"
#endif
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
#include "dwarf2out.h"
#endif
#ifdef SDB_DEBUGGING_INFO
#include "sdbout.h"
#endif
#ifndef N_SLINE
#define N_SLINE 0x44
#endif
#ifndef N_SOL
#define N_SOL 0x84
#endif
#ifndef INT_TYPE_SIZE
#define INT_TYPE_SIZE BITS_PER_WORD
#endif
#ifndef LONG_TYPE_SIZE
#define LONG_TYPE_SIZE BITS_PER_WORD
#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
static rtx debug_insn = 0;
static int last_linenum;
static int high_block_linenum;
static int high_function_linenum;
static char *last_filename;
static int count_basic_blocks;
extern int count_instrumented_arcs;
extern int length_unit_log;
static rtx this_is_asm_operands;
static unsigned int insn_noperands;
static rtx last_ignored_compare = 0;
static int new_block = 1;
int next_block_index;
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;
int profile_label_no;
static int max_block_depth;
static int *pending_blocks;
static int block_depth;
static int app_on;
rtx final_sequence;
#ifdef ASSEMBLER_DIALECT
static int dialect_number;
#endif
static char *line_note_exists;
struct bb_list {
struct bb_list *next;
int line_num;
int file_label_num;
int func_label_num;
};
static struct bb_list *bb_head = 0;
static struct bb_list **bb_tail = &bb_head;
static int bb_file_label_num = -1;
static int bb_func_label_num = -1;
struct bb_str {
struct bb_str *next;
const char *string;
int label_num;
int length;
};
extern rtx peephole PROTO((rtx));
static struct bb_str *sbb_head = 0;
static struct bb_str **sbb_tail = &sbb_head;
static int sbb_label_num = 0;
#ifdef HAVE_ATTR_length
static int asm_insn_count PROTO((rtx));
#endif
static void profile_function PROTO((FILE *));
static void profile_after_prologue PROTO((FILE *));
static void add_bb PROTO((FILE *));
static int add_bb_string PROTO((const char *, int));
static void output_source_line PROTO((FILE *, rtx));
static rtx walk_alter_subreg PROTO((rtx));
static void output_asm_name PROTO((void));
static void output_operand PROTO((rtx, int));
#ifdef LEAF_REGISTERS
static void leaf_renumber_regs PROTO((rtx));
#endif
#ifdef HAVE_cc0
static int alter_cond PROTO((rtx));
#endif
extern char *getpwd ();
void
init_final (filename)
char *filename;
{
next_block_index = 2;
app_on = 0;
max_block_depth = 20;
pending_blocks = (int *) xmalloc (20 * sizeof *pending_blocks);
final_sequence = 0;
#ifdef ASSEMBLER_DIALECT
dialect_number = ASSEMBLER_DIALECT;
#endif
}
void
end_final (filename)
const char *filename;
{
int i;
if (profile_block_flag || profile_arc_flag)
{
char name[20];
int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
int size, rounded;
struct bb_list *ptr;
struct bb_str *sptr;
int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT;
int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT;
if (profile_block_flag)
size = long_bytes * count_basic_blocks;
else
size = long_bytes * count_instrumented_arcs;
rounded = size;
rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
* (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
data_section ();
ASM_OUTPUT_ALIGN (asm_out_file, align);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
assemble_integer (const0_rtx, long_bytes, 1);
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
if (profile_block_flag)
assemble_integer (GEN_INT (count_basic_blocks), long_bytes, 1);
else
assemble_integer (GEN_INT (count_instrumented_arcs), long_bytes,
1);
assemble_integer (const0_rtx, pointer_bytes, 1);
if (profile_block_flag)
{
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
1);
}
else
assemble_integer (const0_rtx, pointer_bytes, 1);
assemble_integer (GEN_INT (11 * UNITS_PER_WORD), long_bytes, 1);
if (profile_block_flag)
{
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 4);
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
1);
}
else
assemble_integer (const0_rtx, pointer_bytes, 1);
if (write_symbols != NO_DEBUG && profile_block_flag)
{
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 5);
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 6);
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
}
else
{
assemble_integer (const0_rtx, pointer_bytes, 1);
assemble_integer (const0_rtx, pointer_bytes, 1);
}
assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
{
char *cwd = getpwd ();
int len = strlen (filename) + strlen (cwd) + 1;
char *data_file = (char *) alloca (len + 4);
strcpy (data_file, cwd);
strcat (data_file, "/");
strcat (data_file, filename);
strip_off_ending (data_file, len);
if (profile_block_flag)
strcat (data_file, ".d");
else
strcat (data_file, ".da");
assemble_string (data_file, strlen (data_file) + 1);
}
if (size == 0)
{
ASM_OUTPUT_ALIGN (asm_out_file, align);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2);
if (size != 0)
assemble_zeros (size);
}
else
{
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
#ifdef ASM_OUTPUT_SHARED_LOCAL
if (flag_shared_data)
ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
else
#endif
#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
BIGGEST_ALIGNMENT);
#else
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
BIGGEST_ALIGNMENT);
#else
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
#endif
#endif
}
if (profile_block_flag)
{
readonly_data_section ();
if (sbb_head)
{
ASM_OUTPUT_ALIGN (asm_out_file, align);
for (sptr = sbb_head; sptr != 0; sptr = sptr->next)
{
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBC",
sptr->label_num);
assemble_string (sptr->string, sptr->length);
}
}
}
if (profile_block_flag)
{
ASM_OUTPUT_ALIGN (asm_out_file, align);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3);
for (i = 0; i < count_basic_blocks; i++)
{
ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i);
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
pointer_bytes, 1);
}
}
if (profile_block_flag)
{
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 4);
for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
{
if (ptr->func_label_num >= 0)
{
ASM_GENERATE_INTERNAL_LABEL (name, "LPBC",
ptr->func_label_num);
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
pointer_bytes, 1);
}
else
assemble_integer (const0_rtx, pointer_bytes, 1);
}
for ( ; i < count_basic_blocks; i++)
assemble_integer (const0_rtx, pointer_bytes, 1);
}
if (write_symbols != NO_DEBUG && profile_block_flag)
{
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 5);
for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
assemble_integer (GEN_INT (ptr->line_num), long_bytes, 1);
for ( ; i < count_basic_blocks; i++)
assemble_integer (const0_rtx, long_bytes, 1);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 6);
for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
{
if (ptr->file_label_num >= 0)
{
ASM_GENERATE_INTERNAL_LABEL (name, "LPBC",
ptr->file_label_num);
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
pointer_bytes, 1);
}
else
assemble_integer (const0_rtx, pointer_bytes, 1);
}
for ( ; i < count_basic_blocks; i++)
assemble_integer (const0_rtx, pointer_bytes, 1);
}
if (profile_block_flag)
{
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
1);
}
}
}
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 short *insn_lengths;
int *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 (label_align)
{
free (label_align);
label_align = 0;
}
if (uid_shuid)
{
free (uid_shuid);
uid_shuid = 0;
}
if (insn_lengths)
{
free (insn_lengths);
insn_lengths = 0;
insn_lengths_max_uid = 0;
}
if (insn_addresses)
{
free (insn_addresses);
insn_addresses = 0;
}
if (uid_align)
{
free (uid_align);
uid_align = 0;
}
}
int
get_attr_length (insn)
rtx insn;
{
#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) 0
#endif
#ifndef LABEL_ALIGN_MAX_SKIP
#define LABEL_ALIGN_MAX_SKIP 0
#endif
#ifndef LOOP_ALIGN
#define LOOP_ALIGN(LABEL) 0
#endif
#ifndef LOOP_ALIGN_MAX_SKIP
#define LOOP_ALIGN_MAX_SKIP 0
#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 ADDR_VEC_ALIGN
int
final_addr_vec_align (addr_vec)
rtx addr_vec;
{
int align = exact_log2 (GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec))));
if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
return 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
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;
rtx seq = NEXT_INSN (PREV_INSN (branch));
int seq_uid = INSN_UID (seq);
if (GET_CODE (branch) != JUMP_INSN)
return insn_current_address;
dest = JUMP_LABEL (branch);
if (INSN_SHUID (branch) < 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
#ifndef FIRST_INSN_ADDRESS
#define FIRST_INSN_ADDRESS 0
#endif
void
shorten_branches (first)
rtx first;
{
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];
for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
rtx old = insn;
if (! INSN_DELETED_P (old))
insn = try_split (PATTERN (old), old, 1);
if (INSN_DELETED_P (old))
{
PUT_CODE (old , NOTE);
NOTE_LINE_NUMBER (old) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (old) = 0;
}
}
#endif
init_insn_lengths ();
max_uid = get_max_uid ();
max_labelno = max_label_num ();
min_labelno = get_first_label_num ();
label_align = (struct label_alignment *) xmalloc (
(max_labelno - min_labelno + 1) * sizeof (struct label_alignment));
bzero ((char *) label_align,
(max_labelno - min_labelno + 1) * sizeof (struct label_alignment));
uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
max_log = 0;
max_skip = 0;
for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
{
int log;
INSN_SHUID (insn) = i++;
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
}
else if (GET_CODE (insn) == CODE_LABEL)
{
rtx next;
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
#if !defined(READONLY_DATA_SECTION)
|| 1
#endif
)
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 && GET_RTX_CLASS (GET_CODE (label)) != 'i';
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;
}
}
else if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
{
rtx label;
for (label = insn; label; label = NEXT_INSN (label))
if (GET_CODE (label) == CODE_LABEL)
{
log = LOOP_ALIGN (insn);
if (max_log < log)
{
max_log = log;
max_skip = LOOP_ALIGN_MAX_SKIP;
}
break;
}
}
else
continue;
}
#ifdef HAVE_ATTR_length
insn_lengths = (short *) xmalloc (max_uid * sizeof (short));
insn_addresses = (int *) xmalloc (max_uid * sizeof (int));
insn_lengths_max_uid = max_uid;
bzero ((char *)insn_addresses, max_uid * sizeof *insn_addresses);
uid_align = (rtx *) xmalloc (max_uid * sizeof *uid_align);
varying_length = (char *) xmalloc (max_uid * sizeof (char));
bzero (varying_length, max_uid);
bzero ((char *) uid_align, 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_current_address = new_address;
}
}
insn_addresses[uid] = insn_current_address;
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
#if !defined(READONLY_DATA_SECTION)
|| 1
#endif
)
insn_lengths[uid] = (XVECLEN (body,
GET_CODE (body) == ADDR_DIFF_VEC)
* GET_MODE_SIZE (GET_MODE (body)));
}
else if (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 (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);
addr_diff_vec_flags flags = ADDR_DIFF_VEC_FLAGS (body);
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;
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
#if !defined(READONLY_DATA_SECTION)
|| 1
#endif
)
{
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]))
{
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;
{
char *template;
int count = 1;
if (GET_CODE (body) == ASM_INPUT)
template = XSTR (body, 0);
else
template = decode_asm_operands (body, NULL_PTR, NULL_PTR,
NULL_PTR, NULL_PTR);
for ( ; *template; template++)
if (IS_ASM_LOGICAL_LINE_SEPARATOR(*template) || *template == '\n')
count++;
return count;
}
#endif
int look_for_jumpto_pattern(first, optimize)
rtx first;
int optimize;
{
int after_call;
rtx insn;
if ( current_function_calls_setjmp )
return 0;
if ( get_frame_size())
return 0;
if ( profile_flag )
return 0;
if ( profile_block_flag )
return 0;
if ( !optimize )
return 0;
if ( current_function_uses_pic_offset_table && flag_pic )
return 0;
after_call = 0;
for (insn=first; insn; insn=NEXT_INSN(insn))
{
switch (GET_CODE (insn))
{
case NOTE:
case CODE_LABEL:
break;
case CALL_INSN:
if ( after_call )
return 0;
after_call = 1;
break;
case INSN:
switch (GET_CODE(PATTERN(insn)))
{
case USE:
case CLOBBER:
break;
case SET:
{
rtx src, dest;
int regno;
if ( after_call )
return 0;
dest = XEXP( PATTERN(insn), 0);
src = XEXP( PATTERN(insn), 1);
if ( GET_CODE(dest) != REG )
return 0;
regno = REGNO( dest);
if ( regno >= FIRST_PSEUDO_REGISTER )
return 0;
if ( !call_used_regs[regno] )
return 0;
if ( GET_CODE(src) == MEM )
return 0;
break;
}
default:
return 0;
}
break;
case JUMP_INSN:
case BARRIER:
default:
return 0;
}
}
return after_call;
}
void
final_start_function (first, file, optimize, jumpto)
rtx first;
FILE *file;
int optimize;
int jumpto;
{
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)
last_linenum = high_block_linenum = high_function_linenum
= NOTE_LINE_NUMBER (first);
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
if (dwarf2out_do_frame ())
dwarf2out_begin_prologue ();
#endif
#if defined(SDB_DEBUGGING_INFO) && !defined(MIPS_DEBUGGING_INFO)
if (write_symbols == SDB_DEBUG)
sdbout_begin_function (last_linenum);
else
#endif
#ifdef XCOFF_DEBUGGING_INFO
if (write_symbols == XCOFF_DEBUG)
xcoffout_begin_function (file, last_linenum);
else
#endif
if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
output_source_line (file, first);
#ifdef LEAF_REG_REMAP
if (current_function_uses_only_leaf_regs)
leaf_renumber_regs (first);
#endif
#ifdef PROFILE_BEFORE_PROLOGUE
if (profile_flag)
profile_function (file);
#endif
#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
if (dwarf2out_do_frame ())
dwarf2out_frame_debug (NULL_RTX);
#endif
#ifdef FUNCTION_PROLOGUE
if ( !jumpto )
FUNCTION_PROLOGUE (file, get_frame_size ());
#endif
#if defined (SDB_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
if (write_symbols == SDB_DEBUG || write_symbols == XCOFF_DEBUG)
next_block_index = 1;
#endif
#ifdef HAVE_prologue
if (! HAVE_prologue)
#endif
profile_after_prologue (file);
profile_label_no++;
if (profile_block_flag)
{
bb_func_label_num
= add_bb_string ((*decl_printable_name) (current_function_decl, 2), FALSE);
}
}
static void
profile_after_prologue (file)
FILE *file;
{
#ifdef FUNCTION_BLOCK_PROFILER
if (profile_block_flag)
{
FUNCTION_BLOCK_PROFILER (file, count_basic_blocks);
}
#endif
#ifndef PROFILE_BEFORE_PROLOGUE
if (profile_flag)
profile_function (file);
#endif
}
static void
profile_function (file)
FILE *file;
{
int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
#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
#if !defined (NEXT_SEMANTICS) || defined (OPENSTEP)
data_section ();
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
#ifdef PROFILE_LABEL_PREFIX
ASM_OUTPUT_INTERNAL_LABEL (file, "_LP", profile_label_no);
#else
ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no);
#endif
assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, 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, profile_label_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 (first, file, optimize, jumpto)
rtx first;
FILE *file;
int optimize;
int jumpto;
{
if (app_on)
{
fputs (ASM_APP_OFF, file);
app_on = 0;
}
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG)
sdbout_end_function (high_function_linenum);
#endif
#ifdef DWARF_DEBUGGING_INFO
if (write_symbols == DWARF_DEBUG)
dwarfout_end_function ();
#endif
#ifdef XCOFF_DEBUGGING_INFO
if (write_symbols == XCOFF_DEBUG)
xcoffout_end_function (file, high_function_linenum);
#endif
#ifdef FUNCTION_EPILOGUE
if (!jumpto )
FUNCTION_EPILOGUE (file, get_frame_size ());
#endif
#ifdef OUTPUT_COMPILER_STUB
output_compiler_stub();
#endif
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG)
sdbout_end_epilogue ();
#endif
#ifdef DWARF_DEBUGGING_INFO
if (write_symbols == DWARF_DEBUG)
dwarfout_end_epilogue ();
#endif
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
if (dwarf2out_do_frame ())
dwarf2out_end_epilogue ();
#endif
#ifdef XCOFF_DEBUGGING_INFO
if (write_symbols == XCOFF_DEBUG)
xcoffout_end_epilogue (file);
#endif
bb_func_label_num = -1;
}
static void
add_bb (file)
FILE *file;
{
struct bb_list *ptr = (struct bb_list *) permalloc (sizeof (struct bb_list));
ptr->next = 0;
ptr->line_num = last_linenum;
ptr->file_label_num = bb_file_label_num;
ptr->func_label_num = bb_func_label_num;
*bb_tail = ptr;
bb_tail = &ptr->next;
ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks);
#ifdef BLOCK_PROFILER
BLOCK_PROFILER (file, count_basic_blocks);
#endif
#ifdef HAVE_cc0
CC_STATUS_INIT;
#endif
new_block = 0;
count_basic_blocks++;
}
static int
add_bb_string (string, perm_p)
const char *string;
int perm_p;
{
int len;
struct bb_str *ptr = 0;
if (!string)
{
string = "<unknown>";
perm_p = TRUE;
}
len = strlen (string) + 1;
if (!perm_p)
{
char *p = (char *) permalloc (len);
bcopy (string, p, len);
string = p;
}
else
for (ptr = sbb_head; ptr != (struct bb_str *) 0; ptr = ptr->next)
if (ptr->string == string)
break;
if (!ptr)
{
ptr = (struct bb_str *) permalloc (sizeof (*ptr));
ptr->next = 0;
ptr->length = len;
ptr->label_num = sbb_label_num++;
ptr->string = string;
*sbb_tail = ptr;
sbb_tail = &ptr->next;
}
return ptr->label_num;
}
void
final (first, file, optimize, prescan, jumpto)
rtx first;
FILE *file;
int optimize;
int prescan;
int jumpto;
{
register rtx insn;
int max_line = 0;
int max_uid = 0;
last_ignored_compare = 0;
new_block = 1;
check_exception_handler_labels ();
#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)))
{
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
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 *) oballoc (max_line + 1);
bzero (line_note_exists, max_line + 1);
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_insn_eh_region (first, max_uid);
init_recog ();
CC_STATUS_INIT;
for (insn = NEXT_INSN (first); insn;)
{
#ifdef HAVE_ATTR_length
insn_current_address = insn_addresses[INSN_UID (insn)];
#endif
insn = final_scan_insn (insn, file, optimize, prescan, 0, jumpto);
}
if (profile_block_flag && new_block)
add_bb (file);
free_insn_eh_region ();
}
rtx
final_scan_insn (insn, file, optimize, prescan, nopeepholes, jumpto)
rtx insn;
FILE *file;
int optimize;
int prescan;
int nopeepholes;
int jumpto;
{
#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;
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
break;
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
break;
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
&& ! exceptions_via_longjmp)
{
ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_BLOCK_NUMBER (insn));
if (! flag_new_exceptions)
add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
#ifdef ASM_OUTPUT_EH_REGION_BEG
ASM_OUTPUT_EH_REGION_BEG (file, NOTE_BLOCK_NUMBER (insn));
#endif
break;
}
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
&& ! exceptions_via_longjmp)
{
ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_BLOCK_NUMBER (insn));
if (flag_new_exceptions)
add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
#ifdef ASM_OUTPUT_EH_REGION_END
ASM_OUTPUT_EH_REGION_END (file, NOTE_BLOCK_NUMBER (insn));
#endif
break;
}
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
{
#ifdef FUNCTION_END_PROLOGUE
FUNCTION_END_PROLOGUE (file);
#endif
profile_after_prologue (file);
break;
}
#ifdef FUNCTION_BEGIN_EPILOGUE
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
{
FUNCTION_BEGIN_EPILOGUE (file);
break;
}
#endif
if (write_symbols == NO_DEBUG)
break;
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
{
#if defined(SDB_DEBUGGING_INFO) && defined(MIPS_DEBUGGING_INFO)
if (write_symbols == SDB_DEBUG)
sdbout_begin_function (last_linenum);
else
#endif
#ifdef DWARF_DEBUGGING_INFO
if (write_symbols == DWARF_DEBUG)
dwarfout_begin_function ();
#endif
break;
}
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
break;
if (app_on)
{
fputs (ASM_APP_OFF, file);
app_on = 0;
}
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
&& (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
|| write_symbols == DWARF_DEBUG
|| write_symbols == DWARF2_DEBUG))
{
if (block_depth == max_block_depth)
{
max_block_depth *= 2;
pending_blocks
= (int *) xrealloc (pending_blocks,
max_block_depth * sizeof (int));
}
pending_blocks[block_depth++] = next_block_index;
high_block_linenum = last_linenum;
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG)
sdbout_begin_block (file, last_linenum, next_block_index);
#endif
#ifdef XCOFF_DEBUGGING_INFO
if (write_symbols == XCOFF_DEBUG)
xcoffout_begin_block (file, last_linenum, next_block_index);
#endif
#ifdef DBX_DEBUGGING_INFO
if (write_symbols == DBX_DEBUG)
ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", next_block_index);
#endif
#ifdef DWARF_DEBUGGING_INFO
if (write_symbols == DWARF_DEBUG)
dwarfout_begin_block (next_block_index);
#endif
#ifdef DWARF2_DEBUGGING_INFO
if (write_symbols == DWARF2_DEBUG)
dwarf2out_begin_block (next_block_index);
#endif
next_block_index++;
}
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
&& (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
|| write_symbols == DWARF_DEBUG
|| write_symbols == DWARF2_DEBUG))
{
--block_depth;
if (block_depth < 0)
abort ();
#ifdef XCOFF_DEBUGGING_INFO
if (write_symbols == XCOFF_DEBUG)
xcoffout_end_block (file, high_block_linenum,
pending_blocks[block_depth]);
#endif
#ifdef DBX_DEBUGGING_INFO
if (write_symbols == DBX_DEBUG)
ASM_OUTPUT_INTERNAL_LABEL (file, "LBE",
pending_blocks[block_depth]);
#endif
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG)
sdbout_end_block (file, high_block_linenum,
pending_blocks[block_depth]);
#endif
#ifdef DWARF_DEBUGGING_INFO
if (write_symbols == DWARF_DEBUG)
dwarfout_end_block (pending_blocks[block_depth]);
#endif
#ifdef DWARF2_DEBUGGING_INFO
if (write_symbols == DWARF2_DEBUG)
dwarf2out_end_block (pending_blocks[block_depth]);
#endif
}
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL
&& (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE))
{
#ifdef DWARF_DEBUGGING_INFO
if (write_symbols == DWARF_DEBUG)
dwarfout_label (insn);
#endif
#ifdef DWARF2_DEBUGGING_INFO
if (write_symbols == DWARF2_DEBUG)
dwarf2out_label (insn);
#endif
}
else if (NOTE_LINE_NUMBER (insn) > 0)
{
register rtx note;
#if 0
output_source_line (file, insn);
#endif
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)
output_source_line (file, insn);
}
break;
case BARRIER:
#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS)
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
ASM_OUTPUT_ALIGN (file, align);
#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_PTR, 0);
#endif
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG && LABEL_NAME (insn))
sdbout_label (insn);
#endif
#ifdef DWARF_DEBUGGING_INFO
if (write_symbols == DWARF_DEBUG && LABEL_NAME (insn))
dwarfout_label (insn);
#endif
#ifdef DWARF2_DEBUGGING_INFO
if (write_symbols == DWARF2_DEBUG && LABEL_NAME (insn))
dwarf2out_label (insn);
#endif
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)
{
readonly_data_section ();
#ifdef READONLY_DATA_SECTION
ASM_OUTPUT_ALIGN (file,
exact_log2 (BIGGEST_ALIGNMENT
/ BITS_PER_UNIT));
#endif
}
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;
}
}
#ifdef PREPROCESS_INTERNAL_LABEL
PREPROCESS_INTERNAL_LABEL (file, insn);
#endif
ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
#ifdef NEXT_SEMANTICS
if (XSTR (insn, 4) && (XSTR (insn, 4))[0] == '*')
assemble_label (XSTR (insn, 4));
#endif
break;
default:
{
register rtx body = PATTERN (insn);
int insn_code_number;
const char *template;
#ifdef HAVE_cc0
rtx note;
#endif
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))
register 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 (profile_block_flag && new_block)
add_bb (file);
if (GET_CODE (body) == ASM_INPUT)
{
CC_STATUS_INIT;
if (prescan > 0)
break;
if (! app_on)
{
fputs (ASM_APP_ON, file);
app_on = 1;
}
fprintf (asm_out_file, "\t%s\n", XSTR (body, 0));
break;
}
if (asm_noperands (body) >= 0)
{
unsigned int noperands = asm_noperands (body);
rtx *ops = (rtx *) alloca (noperands * sizeof (rtx));
char *string;
CC_STATUS_INIT;
if (prescan > 0)
break;
if (! app_on)
{
fputs (ASM_APP_ON, file);
app_on = 1;
}
string = decode_asm_operands (body, ops, NULL_PTR,
NULL_PTR, NULL_PTR);
insn_noperands = noperands;
this_is_asm_operands = insn;
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)
{
register int i;
rtx next;
if (prescan > 0)
break;
final_sequence = body;
next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1, jumpto);
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, jumpto);
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;
}
if (profile_block_flag)
{
rtx insn = XVECEXP (body, 0, 0);
rtx body = PATTERN (insn);
if ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
&& GET_CODE (SET_SRC (body)) != LABEL_REF)
|| (GET_CODE (insn) == JUMP_INSN
&& GET_CODE (body) == PARALLEL
&& GET_CODE (XVECEXP (body, 0, 0)) == SET
&& GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF))
new_block = 1;
}
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, 0)
&& ! volatile_refs_p (PATTERN (insn)))
{
last_ignored_compare = insn;
break;
}
}
}
}
#endif
if (profile_block_flag && final_sequence == 0
&& ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
&& GET_CODE (SET_SRC (body)) != LABEL_REF)
|| (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == PARALLEL
&& GET_CODE (XVECEXP (body, 0, 0)) == SET
&& GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF)))
new_block = 1;
#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)
{
register 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)
{
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
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:
{
register 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))
{
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
}
}
break;
default:
break;
}
}
#endif
if (optimize && !flag_no_peephole && !nopeepholes)
{
rtx next = peephole (insn);
if (next != 0 && next != NEXT_INSN (insn))
{
rtx prev = PREV_INSN (insn);
rtx note;
for (note = NEXT_INSN (insn); note != next;
note = NEXT_INSN (note))
final_scan_insn (note, file, optimize, prescan, nopeepholes, jumpto);
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);
}
insn_code_number = recog_memoized (insn);
extract_insn (insn);
cleanup_subreg_operands (insn);
#ifdef REGISTER_CONSTRAINTS
if (! constrain_operands (1))
fatal_insn_not_found (insn);
#endif
#ifdef FINAL_PRESCAN_INSN
FINAL_PRESCAN_INSN (insn, recog_operand, recog_n_operands);
#endif
#ifdef HAVE_cc0
cc_prev_status = cc_status;
NOTICE_UPDATE_CC (body, insn);
#endif
debug_insn = insn;
#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS)
if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ())
dwarf2out_frame_debug (insn);
#endif
template = insn_template[insn_code_number];
if (template == 0)
{
template = (*insn_outfun[insn_code_number]) (recog_operand, insn);
if (template == 0)
{
if (prev_nonnote_insn (insn) != last_ignored_compare)
abort ();
new_block = 0;
return prev_nonnote_insn (insn);
}
}
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;
#if defined (NEXT_SEMANTICS) && defined (TARGET_TOC)
if (jumpto && GET_CODE (insn) == CALL_INSN )
{
char *template2 = strcpy (alloca (strlen (template)+1), template);
if ( strncmp (template, "bl %z", 5) == 0)
{
template2[1] = ' ';
output_asm_insn (template2, recog_operand);
}
else if ( strcmp (&template[strlen(template)]-5, "bctrl") == 0)
{
template2[strlen(template)-1] = ' ';
output_asm_insn (template2, recog_operand);
}
}
else
#endif
output_asm_insn (template, recog_operand);
#if defined (DWARF2_UNWIND_INFO)
#if !defined (ACCUMULATE_OUTGOING_ARGS)
if (GET_CODE (insn) == INSN && dwarf2out_do_frame ())
dwarf2out_frame_debug (insn);
#else
#if defined (HAVE_prologue)
if (RTX_FRAME_RELATED_P (insn) && dwarf2out_do_frame ())
dwarf2out_frame_debug (insn);
#endif
#endif
#endif
#if 0
INSN_DELETED_P (insn) = 1;
#endif
debug_insn = 0;
}
}
return NEXT_INSN (insn);
}
static void
output_source_line (file, insn)
FILE *file;
rtx insn;
{
register char *filename = NOTE_SOURCE_FILE (insn);
if (profile_block_flag && last_filename != filename)
bb_file_label_num = add_bb_string (filename, TRUE);
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);
if (write_symbols != NO_DEBUG)
{
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG
#if 0
&& !strcmp (filename, main_input_filename)
#endif
&& last_linenum > sdb_begin_function_line)
{
#ifdef ASM_OUTPUT_SOURCE_LINE
ASM_OUTPUT_SOURCE_LINE (file, last_linenum);
#else
fprintf (file, "\t.ln\t%d\n",
((sdb_begin_function_line > -1)
? last_linenum - sdb_begin_function_line : 1));
#endif
}
#endif
#if defined (DBX_DEBUGGING_INFO)
if (write_symbols == DBX_DEBUG)
dbxout_source_line (file, filename, NOTE_LINE_NUMBER (insn));
#endif
#if defined (XCOFF_DEBUGGING_INFO)
if (write_symbols == XCOFF_DEBUG)
xcoffout_source_line (file, filename, insn);
#endif
#ifdef DWARF_DEBUGGING_INFO
if (write_symbols == DWARF_DEBUG)
dwarfout_line (filename, NOTE_LINE_NUMBER (insn));
#endif
#ifdef DWARF2_DEBUGGING_INFO
if (write_symbols == DWARF2_DEBUG)
dwarf2out_line (filename, NOTE_LINE_NUMBER (insn));
#endif
}
}
void
cleanup_subreg_operands (insn)
rtx insn;
{
int i;
extract_insn (insn);
for (i = 0; i < recog_n_operands; i++)
{
if (GET_CODE (recog_operand[i]) == SUBREG)
recog_operand[i] = alter_subreg (recog_operand[i]);
else if (GET_CODE (recog_operand[i]) == PLUS
|| GET_CODE (recog_operand[i]) == MULT)
recog_operand[i] = walk_alter_subreg (recog_operand[i]);
}
for (i = 0; i < recog_n_dups; i++)
{
if (GET_CODE (*recog_dup_loc[i]) == SUBREG)
*recog_dup_loc[i] = alter_subreg (*recog_dup_loc[i]);
else if (GET_CODE (*recog_dup_loc[i]) == PLUS
|| GET_CODE (*recog_dup_loc[i]) == MULT)
*recog_dup_loc[i] = walk_alter_subreg (*recog_dup_loc[i]);
}
}
rtx
alter_subreg (x)
register rtx x;
{
register rtx y = SUBREG_REG (x);
if (GET_CODE (y) == SUBREG)
y = alter_subreg (y);
if (reload_in_progress && find_replacement (&SUBREG_REG (x)) != 0)
x = copy_rtx (x);
if (GET_CODE (y) == REG)
{
PUT_CODE (x, REG);
#ifdef ALTER_HARD_SUBREG
REGNO (x) = ALTER_HARD_SUBREG(GET_MODE (x), SUBREG_WORD (x),
GET_MODE (y), REGNO (y));
#else
REGNO (x) = REGNO (y) + SUBREG_WORD (x);
#endif
x->used = 0;
}
else if (GET_CODE (y) == MEM)
{
register int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
if (BYTES_BIG_ENDIAN)
offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))
- MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));
PUT_CODE (x, MEM);
MEM_COPY_ATTRIBUTES (x, y);
MEM_ALIAS_SET (x) = MEM_ALIAS_SET (y);
XEXP (x, 0) = plus_constant_for_output (XEXP (y, 0), offset);
}
return x;
}
static rtx
walk_alter_subreg (x)
rtx x;
{
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 (x);
default:
break;
}
return x;
}
#ifdef HAVE_cc0
static int
alter_cond (cond)
register 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 (msgid)
const char *msgid;
{
if (this_is_asm_operands)
error_for_asm (this_is_asm_operands, "invalid `asm': %s", _(msgid));
else
fatal ("Internal compiler error, output_operand_lossage `%s'", _(msgid));
}
static void
output_asm_name ()
{
if (flag_print_asm_name)
{
if (debug_insn)
{
register int num = INSN_CODE (debug_insn);
fprintf (asm_out_file, "\t%s %d\t%s",
ASM_COMMENT_START, INSN_UID (debug_insn), insn_name[num]);
if (insn_n_alternatives[num] > 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;
}
}
}
void
output_asm_insn (template, operands)
const char *template;
rtx *operands;
{
register const char *p;
register int c;
if (*template == 0)
return;
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':
output_asm_name ();
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 '{':
{
register 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 '%':
if (*p == '%')
{
p++;
putc (c, asm_out_file);
}
else if (*p == '=')
{
p++;
fprintf (asm_out_file, "%d", insn_counter);
}
else if ((*p >= 'a' && *p <= 'z')
|| (*p >= 'A' && *p <= 'Z'))
{
int letter = *p++;
c = atoi (p);
if (! (*p >= '0' && *p <= '9'))
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);
while ((c = *p) >= '0' && c <= '9') p++;
}
else if (*p >= '0' && *p <= '9')
{
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);
while ((c = *p) >= '0' && c <= '9') 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;
#if defined (NEXT_SEMANTICS) && defined (HPPA)
case '\'':
if (*(p-2) && strchr("RLTP", *(p-2)))
{
putc ('`', asm_out_file);
break;
}
#endif
default:
putc (c, asm_out_file);
}
output_asm_name ();
putc ('\n', asm_out_file);
}
void
output_asm_label (x)
rtx x;
{
char buf[256];
if (GET_CODE (x) == LABEL_REF)
ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
else if (GET_CODE (x) == CODE_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;
{
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:
if (flag_pic)
putc ('.', file);
else
abort ();
break;
case SYMBOL_REF:
assemble_name (file, XSTR (x, 0));
break;
case LABEL_REF:
ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
assemble_name (file, buf);
break;
case CODE_LABEL:
ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
assemble_name (file, buf);
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 (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)
{
fprintf (file, ASM_OPEN_PAREN);
output_addr_const (file, XEXP (x, 1));
fprintf (file, ASM_CLOSE_PAREN);
}
else
output_addr_const (file, XEXP (x, 1));
break;
case ZERO_EXTEND:
case SIGN_EXTEND:
output_addr_const (file, XEXP (x, 0));
break;
default:
output_operand_lossage ("invalid expression as operand");
}
}
void
asm_fprintf VPROTO((FILE *file, const char *p, ...))
{
#ifndef ANSI_PROTOTYPES
FILE *file;
const char *p;
#endif
va_list argptr;
char buf[10];
char *q, c;
VA_START (argptr, p);
#ifndef ANSI_PROTOTYPES
file = va_arg (argptr, FILE *);
p = va_arg (argptr, const char *);
#endif
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 ((c >= '0' && c <= '9') || 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 NEXT_SEMANTICS
case 'S':
*q++ = c;
*q = 0;
assemble_name (file, va_arg (argptr, char*));
break;
#endif
default:
abort ();
}
break;
default:
fputc (c, file);
}
}
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))
{
rtx low, high;
int rshift = HOST_BITS_PER_WIDE_INT - BITS_PER_WORD;
int lshift = HOST_BITS_PER_WIDE_INT - 2 * BITS_PER_WORD;
low = GEN_INT ((INTVAL (value) << rshift) >> rshift);
high = GEN_INT ((INTVAL (value) << lshift) >> rshift);
if (WORDS_BIG_ENDIAN)
{
*first = high;
*second = low;
}
else
{
*first = low;
*second = 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
{
#ifdef REAL_ARITHMETIC
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]);
#else
if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
|| HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
&& ! flag_pretend_float)
abort ();
if (
#ifdef HOST_WORDS_BIG_ENDIAN
WORDS_BIG_ENDIAN
#else
! WORDS_BIG_ENDIAN
#endif
)
{
*first = GEN_INT (CONST_DOUBLE_LOW (value));
*second = GEN_INT (CONST_DOUBLE_HIGH (value));
}
else
{
*second = GEN_INT (CONST_DOUBLE_LOW (value));
*first = GEN_INT (CONST_DOUBLE_HIGH (value));
}
#endif
}
}
int
leaf_function_p ()
{
rtx insn;
if (profile_flag || profile_block_flag || profile_arc_flag)
return 0;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == CALL_INSN)
return 0;
if (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SEQUENCE
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN)
return 0;
}
for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1))
{
if (GET_CODE (XEXP (insn, 0)) == CALL_INSN)
return 0;
if (GET_CODE (XEXP (insn, 0)) == INSN
&& GET_CODE (PATTERN (XEXP (insn, 0))) == SEQUENCE
&& GET_CODE (XVECEXP (PATTERN (XEXP (insn, 0)), 0, 0)) == CALL_INSN)
return 0;
}
return 1;
}
#ifdef LEAF_REGISTERS
static char permitted_reg_in_leaf_functions[] = LEAF_REGISTERS;
int
only_leaf_regs_used ()
{
int i;
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 (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
leaf_renumber_regs_insn (PATTERN (insn));
for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1))
if (GET_RTX_CLASS (GET_CODE (XEXP (insn, 0))) == 'i')
leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0)));
}
void
leaf_renumber_regs_insn (in_rtx)
register rtx in_rtx;
{
register int i, j;
register 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 (GET_RTX_CLASS (GET_CODE (in_rtx)) == 'i')
{
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