#include "config.h"
#include "system.h"
#include "toplev.h"
#include "rtl.h"
#include "tree.h"
#include "tm_p.h"
#include "flags.h"
#include "function.h"
#include "expr.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "hashtab.h"
#include "insn-config.h"
#include "recog.h"
#include "real.h"
#include "obstack.h"
#include "bitmap.h"
#include "basic-block.h"
#include "ggc.h"
#include "debug.h"
#include "langhooks.h"
#ifdef PFE
#include "pfe/pfe.h"
#include "pfe/pfe-header.h"
#endif
enum machine_mode byte_mode;
enum machine_mode word_mode;
enum machine_mode double_mode;
enum machine_mode ptr_mode;
static int label_num = 1;
static int last_label_num;
static int base_label_num;
static int no_line_numbers;
rtx global_rtl[GR_MAX];
rtx const_tiny_rtx[3][(int) MAX_MACHINE_MODE];
rtx const_true_rtx;
REAL_VALUE_TYPE dconst0;
REAL_VALUE_TYPE dconst1;
REAL_VALUE_TYPE dconst2;
REAL_VALUE_TYPE dconstm1;
rtx struct_value_rtx;
rtx struct_value_incoming_rtx;
rtx static_chain_rtx;
rtx static_chain_incoming_rtx;
rtx pic_offset_table_rtx;
rtx return_address_pointer_rtx;
rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
static htab_t const_int_htab;
static htab_t mem_attrs_htab;
#define SEQUENCE_RESULT_SIZE 5
static rtx sequence_result[SEQUENCE_RESULT_SIZE];
static rtx free_insn;
#define first_insn (cfun->emit->x_first_insn)
#define last_insn (cfun->emit->x_last_insn)
#define cur_insn_uid (cfun->emit->x_cur_insn_uid)
#define last_linenum (cfun->emit->x_last_linenum)
#define last_filename (cfun->emit->x_last_filename)
#define first_label_num (cfun->emit->x_first_label_num)
static rtx make_jump_insn_raw PARAMS ((rtx));
static rtx make_call_insn_raw PARAMS ((rtx));
static rtx find_line_note PARAMS ((rtx));
static void mark_sequence_stack PARAMS ((struct sequence_stack *));
static rtx change_address_1 PARAMS ((rtx, enum machine_mode, rtx,
int));
static void unshare_all_rtl_1 PARAMS ((rtx));
static void unshare_all_decls PARAMS ((tree));
static void reset_used_decls PARAMS ((tree));
static void mark_label_nuses PARAMS ((rtx));
static hashval_t const_int_htab_hash PARAMS ((const void *));
static int const_int_htab_eq PARAMS ((const void *,
const void *));
static hashval_t mem_attrs_htab_hash PARAMS ((const void *));
static int mem_attrs_htab_eq PARAMS ((const void *,
const void *));
static void mem_attrs_mark PARAMS ((const void *));
static mem_attrs *get_mem_attrs PARAMS ((HOST_WIDE_INT, tree, rtx,
rtx, unsigned int,
enum machine_mode));
static tree component_ref_for_mem_expr PARAMS ((tree));
static rtx gen_const_vector_0 PARAMS ((enum machine_mode));
int split_branch_probability = -1;
static hashval_t
const_int_htab_hash (x)
const void *x;
{
return (hashval_t) INTVAL ((const struct rtx_def *) x);
}
static int
const_int_htab_eq (x, y)
const void *x;
const void *y;
{
return (INTVAL ((const struct rtx_def *) x) == *((const HOST_WIDE_INT *) y));
}
static hashval_t
mem_attrs_htab_hash (x)
const void *x;
{
mem_attrs *p = (mem_attrs *) x;
return (p->alias ^ (p->align * 1000)
^ ((p->offset ? INTVAL (p->offset) : 0) * 50000)
^ ((p->size ? INTVAL (p->size) : 0) * 2500000)
^ (size_t) p->expr);
}
static int
mem_attrs_htab_eq (x, y)
const void *x;
const void *y;
{
mem_attrs *p = (mem_attrs *) x;
mem_attrs *q = (mem_attrs *) y;
return (p->alias == q->alias && p->expr == q->expr && p->offset == q->offset
&& p->size == q->size && p->align == q->align);
}
static void
mem_attrs_mark (x)
const void *x;
{
mem_attrs *p = (mem_attrs *) x;
if (p->expr)
ggc_mark_tree (p->expr);
if (p->offset)
ggc_mark_rtx (p->offset);
if (p->size)
ggc_mark_rtx (p->size);
}
static mem_attrs *
get_mem_attrs (alias, expr, offset, size, align, mode)
HOST_WIDE_INT alias;
tree expr;
rtx offset;
rtx size;
unsigned int align;
enum machine_mode mode;
{
mem_attrs attrs;
void **slot;
if (alias == 0 && expr == 0 && offset == 0
&& (size == 0
|| (mode != BLKmode && GET_MODE_SIZE (mode) == INTVAL (size)))
&& (align == BITS_PER_UNIT
|| (STRICT_ALIGNMENT
&& mode != BLKmode && align == GET_MODE_ALIGNMENT (mode))))
return 0;
attrs.alias = alias;
attrs.expr = expr;
attrs.offset = offset;
attrs.size = size;
attrs.align = align;
slot = htab_find_slot (mem_attrs_htab, &attrs, INSERT);
if (*slot == 0)
{
*slot = GGC_ALLOC (sizeof (mem_attrs), PFE_ALLOC_GGC_MEM_ATTRS);
memcpy (*slot, &attrs, sizeof (mem_attrs));
}
return *slot;
}
rtx
gen_raw_REG (mode, regno)
enum machine_mode mode;
int regno;
{
rtx x = gen_rtx_raw_REG (mode, regno);
ORIGINAL_REGNO (x) = regno;
return x;
}
rtx
gen_rtx_CONST_INT (mode, arg)
enum machine_mode mode ATTRIBUTE_UNUSED;
HOST_WIDE_INT arg;
{
void **slot;
if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT)
return const_int_rtx[arg + MAX_SAVED_CONST_INT];
#if STORE_FLAG_VALUE != 1 && STORE_FLAG_VALUE != -1
if (const_true_rtx && arg == STORE_FLAG_VALUE)
return const_true_rtx;
#endif
slot = htab_find_slot_with_hash (const_int_htab, &arg,
(hashval_t) arg, INSERT);
if (*slot == 0)
*slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
return (rtx) *slot;
}
rtx
gen_rtx_CONST_DOUBLE (mode, arg0, arg1)
enum machine_mode mode;
HOST_WIDE_INT arg0, arg1;
{
rtx r = rtx_alloc (CONST_DOUBLE);
int i;
PUT_MODE (r, mode);
X0EXP (r, 0) = NULL_RTX;
XWINT (r, 1) = arg0;
XWINT (r, 2) = arg1;
for (i = GET_RTX_LENGTH (CONST_DOUBLE) - 1; i > 2; --i)
XWINT (r, i) = 0;
return r;
}
rtx
gen_rtx_REG (mode, regno)
enum machine_mode mode;
int regno;
{
if (mode == Pmode && !reload_in_progress)
{
if (regno == FRAME_POINTER_REGNUM)
return frame_pointer_rtx;
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
if (regno == HARD_FRAME_POINTER_REGNUM)
return hard_frame_pointer_rtx;
#endif
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
if (regno == ARG_POINTER_REGNUM)
return arg_pointer_rtx;
#endif
#ifdef RETURN_ADDRESS_POINTER_REGNUM
if (regno == RETURN_ADDRESS_POINTER_REGNUM)
return return_address_pointer_rtx;
#endif
if (regno == PIC_OFFSET_TABLE_REGNUM
&& fixed_regs[PIC_OFFSET_TABLE_REGNUM])
return pic_offset_table_rtx;
if (regno == STACK_POINTER_REGNUM)
return stack_pointer_rtx;
}
return gen_raw_REG (mode, regno);
}
rtx
gen_rtx_MEM (mode, addr)
enum machine_mode mode;
rtx addr;
{
rtx rt = gen_rtx_raw_MEM (mode, addr);
MEM_ATTRS (rt) = 0;
return rt;
}
rtx
gen_rtx_SUBREG (mode, reg, offset)
enum machine_mode mode;
rtx reg;
int offset;
{
if ((offset % GET_MODE_SIZE (mode)) != 0)
abort ();
#if 0
if (offset >= GET_MODE_SIZE (GET_MODE (reg)))
abort ();
#endif
return gen_rtx_fmt_ei (SUBREG, mode, reg, offset);
}
rtx
gen_lowpart_SUBREG (mode, reg)
enum machine_mode mode;
rtx reg;
{
enum machine_mode inmode;
inmode = GET_MODE (reg);
if (inmode == VOIDmode)
inmode = mode;
return gen_rtx_SUBREG (mode, reg,
subreg_lowpart_offset (mode, inmode));
}
rtx
gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
{
int i;
const char *fmt;
rtx rt_val;
VA_OPEN (p, mode);
VA_FIXEDARG (p, enum rtx_code, code);
VA_FIXEDARG (p, enum machine_mode, mode);
switch (code)
{
case CONST_INT:
rt_val = gen_rtx_CONST_INT (mode, va_arg (p, HOST_WIDE_INT));
break;
case CONST_DOUBLE:
{
HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT);
HOST_WIDE_INT arg1 = va_arg (p, HOST_WIDE_INT);
rt_val = gen_rtx_CONST_DOUBLE (mode, arg0, arg1);
}
break;
case REG:
rt_val = gen_rtx_REG (mode, va_arg (p, int));
break;
case MEM:
rt_val = gen_rtx_MEM (mode, va_arg (p, rtx));
break;
default:
rt_val = rtx_alloc (code);
rt_val->mode = mode;
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++)
{
switch (*fmt++)
{
case '0':
break;
case 'i':
XINT (rt_val, i) = va_arg (p, int);
break;
case 'w':
XWINT (rt_val, i) = va_arg (p, HOST_WIDE_INT);
break;
case 's':
XSTR (rt_val, i) = va_arg (p, char *);
break;
case 'e':
case 'u':
XEXP (rt_val, i) = va_arg (p, rtx);
break;
case 'E':
XVEC (rt_val, i) = va_arg (p, rtvec);
break;
case 'b':
XBITMAP (rt_val, i) = va_arg (p, bitmap);
break;
case 't':
XTREE (rt_val, i) = va_arg (p, tree);
break;
default:
abort ();
}
}
break;
}
VA_CLOSE (p);
return rt_val;
}
rtvec
gen_rtvec VPARAMS ((int n, ...))
{
int i, save_n;
rtx *vector;
VA_OPEN (p, n);
VA_FIXEDARG (p, int, n);
if (n == 0)
return NULL_RTVEC;
vector = (rtx *) alloca (n * sizeof (rtx));
for (i = 0; i < n; i++)
vector[i] = va_arg (p, rtx);
save_n = n;
VA_CLOSE (p);
return gen_rtvec_v (save_n, vector);
}
rtvec
gen_rtvec_v (n, argp)
int n;
rtx *argp;
{
int i;
rtvec rt_val;
if (n == 0)
return NULL_RTVEC;
rt_val = rtvec_alloc (n);
for (i = 0; i < n; i++)
rt_val->elem[i] = *argp++;
return rt_val;
}
rtx
gen_reg_rtx (mode)
enum machine_mode mode;
{
struct function *f = cfun;
rtx val;
if (no_new_pseudos)
abort ();
if (generating_concat_p
&& (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_INT))
{
rtx realpart, imagpart;
int size = GET_MODE_UNIT_SIZE (mode);
enum machine_mode partmode
= mode_for_size (size * BITS_PER_UNIT,
(GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
? MODE_FLOAT : MODE_INT),
0);
realpart = gen_reg_rtx (partmode);
imagpart = gen_reg_rtx (partmode);
return gen_rtx_CONCAT (mode, realpart, imagpart);
}
if (reg_rtx_no == f->emit->regno_pointer_align_length)
{
int old_size = f->emit->regno_pointer_align_length;
char *new;
rtx *new1;
tree *new2;
new = PFE_REALLOC (f->emit->regno_pointer_align, old_size * 2,
PFE_ALLOC_REGNO_POINTER_ALIGN);
memset (new + old_size, 0, old_size);
f->emit->regno_pointer_align = (unsigned char *) new;
new1 = (rtx *) PFE_REALLOC (f->emit->x_regno_reg_rtx,
old_size * 2 * sizeof (rtx),
PFE_ALLOC_REGNO_REG_RTX);
memset (new1 + old_size, 0, old_size * sizeof (rtx));
regno_reg_rtx = new1;
new2 = (tree *) PFE_REALLOC (f->emit->regno_decl,
old_size * 2 * sizeof (tree),
PFE_ALLOC_REGNO_DECL);
memset (new2 + old_size, 0, old_size * sizeof (tree));
f->emit->regno_decl = new2;
f->emit->regno_pointer_align_length = old_size * 2;
}
val = gen_raw_REG (mode, reg_rtx_no);
regno_reg_rtx[reg_rtx_no++] = val;
return val;
}
void
mark_user_reg (reg)
rtx reg;
{
if (GET_CODE (reg) == CONCAT)
{
REG_USERVAR_P (XEXP (reg, 0)) = 1;
REG_USERVAR_P (XEXP (reg, 1)) = 1;
}
else if (GET_CODE (reg) == REG)
REG_USERVAR_P (reg) = 1;
else
abort ();
}
void
mark_reg_pointer (reg, align)
rtx reg;
int align;
{
if (! REG_POINTER (reg))
{
REG_POINTER (reg) = 1;
if (align)
REGNO_POINTER_ALIGN (REGNO (reg)) = align;
}
else if (align && align < REGNO_POINTER_ALIGN (REGNO (reg)))
REGNO_POINTER_ALIGN (REGNO (reg)) = align;
}
int
max_reg_num ()
{
return reg_rtx_no;
}
int
max_label_num ()
{
if (last_label_num && label_num == base_label_num)
return last_label_num;
return label_num;
}
int
get_first_label_num ()
{
return first_label_num;
}
int
subreg_hard_regno (x, check_mode)
rtx x;
int check_mode;
{
enum machine_mode mode = GET_MODE (x);
unsigned int byte_offset, base_regno, final_regno;
rtx reg = SUBREG_REG (x);
if (GET_CODE (x) != SUBREG
|| GET_CODE (reg) != REG)
abort ();
base_regno = REGNO (reg);
if (base_regno >= FIRST_PSEUDO_REGISTER)
abort ();
if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
abort ();
byte_offset = SUBREG_BYTE (x);
if ((byte_offset % GET_MODE_SIZE (mode)) != 0)
abort ();
final_regno = subreg_regno (x);
return final_regno;
}
rtx
gen_lowpart_common (mode, x)
enum machine_mode mode;
rtx x;
{
int msize = GET_MODE_SIZE (mode);
int xsize = GET_MODE_SIZE (GET_MODE (x));
int offset = 0;
if (GET_MODE (x) == mode)
return x;
if (GET_MODE (x) != VOIDmode
&& ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD
> ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
return 0;
offset = subreg_lowpart_offset (mode, GET_MODE (x));
if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
&& (GET_MODE_CLASS (mode) == MODE_INT
|| GET_MODE_CLASS (mode) == MODE_PARTIAL_INT))
{
if (GET_MODE (XEXP (x, 0)) == mode)
return XEXP (x, 0);
else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (XEXP (x, 0))))
return gen_lowpart_common (mode, XEXP (x, 0));
else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x)))
return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0));
}
else if (GET_CODE (x) == SUBREG || GET_CODE (x) == REG
|| GET_CODE (x) == CONCAT)
return simplify_gen_subreg (mode, x, GET_MODE (x), offset);
else if ((GET_MODE_CLASS (mode) == MODE_INT
|| GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
&& GET_MODE (x) == VOIDmode
&& (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE))
{
if (GET_MODE_BITSIZE (mode) >= 2 * HOST_BITS_PER_WIDE_INT)
return x;
else if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
return 0;
else if (GET_MODE_BITSIZE (mode) == HOST_BITS_PER_WIDE_INT)
return (GET_CODE (x) == CONST_INT ? x
: GEN_INT (CONST_DOUBLE_LOW (x)));
else
{
HOST_WIDE_INT val = (GET_CODE (x) == CONST_INT ? INTVAL (x)
: CONST_DOUBLE_LOW (x));
val = trunc_int_for_mode (val, mode);
return (GET_CODE (x) == CONST_INT && INTVAL (x) == val ? x
: GEN_INT (val));
}
}
#ifndef REAL_ARITHMETIC
else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
|| flag_pretend_float)
&& GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_SIZE (mode) == UNITS_PER_WORD
&& GET_CODE (x) == CONST_INT
&& sizeof (float) * HOST_BITS_PER_CHAR == HOST_BITS_PER_WIDE_INT)
{
union {HOST_WIDE_INT i; float d; } u;
u.i = INTVAL (x);
return CONST_DOUBLE_FROM_REAL_VALUE (u.d, mode);
}
else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
|| flag_pretend_float)
&& GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
&& (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
&& GET_MODE (x) == VOIDmode
&& (sizeof (double) * HOST_BITS_PER_CHAR
== 2 * HOST_BITS_PER_WIDE_INT))
{
union {HOST_WIDE_INT i[2]; double d; } u;
HOST_WIDE_INT low, high;
if (GET_CODE (x) == CONST_INT)
low = INTVAL (x), high = low >> (HOST_BITS_PER_WIDE_INT -1);
else
low = CONST_DOUBLE_LOW (x), high = CONST_DOUBLE_HIGH (x);
#ifdef HOST_WORDS_BIG_ENDIAN
u.i[0] = high, u.i[1] = low;
#else
u.i[0] = low, u.i[1] = high;
#endif
return CONST_DOUBLE_FROM_REAL_VALUE (u.d, mode);
}
else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
|| flag_pretend_float)
&& (GET_MODE_CLASS (mode) == MODE_INT
|| GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
&& GET_CODE (x) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT
&& GET_MODE_BITSIZE (mode) == BITS_PER_WORD)
return constant_subword (x, (offset / UNITS_PER_WORD), GET_MODE (x));
else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
|| flag_pretend_float)
&& (GET_MODE_CLASS (mode) == MODE_INT
|| GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
&& GET_CODE (x) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT
&& GET_MODE_BITSIZE (mode) == 2 * BITS_PER_WORD)
{
rtx lowpart, highpart;
lowpart = constant_subword (x,
(offset / UNITS_PER_WORD) + WORDS_BIG_ENDIAN,
GET_MODE (x));
highpart = constant_subword (x,
(offset / UNITS_PER_WORD) + (! WORDS_BIG_ENDIAN),
GET_MODE (x));
if (lowpart && GET_CODE (lowpart) == CONST_INT
&& highpart && GET_CODE (highpart) == CONST_INT)
return immed_double_const (INTVAL (lowpart), INTVAL (highpart), mode);
}
#else
else if (GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_BITSIZE (mode) == 32
&& GET_CODE (x) == CONST_INT)
{
REAL_VALUE_TYPE r;
HOST_WIDE_INT i;
i = INTVAL (x);
r = REAL_VALUE_FROM_TARGET_SINGLE (i);
return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
}
else if (GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_BITSIZE (mode) == 64
&& (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
&& GET_MODE (x) == VOIDmode)
{
REAL_VALUE_TYPE r;
HOST_WIDE_INT i[2];
HOST_WIDE_INT low, high;
if (GET_CODE (x) == CONST_INT)
{
low = INTVAL (x);
high = low >> (HOST_BITS_PER_WIDE_INT - 1);
}
else
{
low = CONST_DOUBLE_LOW (x);
high = CONST_DOUBLE_HIGH (x);
}
#if HOST_BITS_PER_WIDE_INT == 32
if (WORDS_BIG_ENDIAN)
i[0] = high, i[1] = low;
else
i[0] = low, i[1] = high;
#else
i[0] = low;
#endif
r = REAL_VALUE_FROM_TARGET_DOUBLE (i);
return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
}
else if ((GET_MODE_CLASS (mode) == MODE_INT
|| GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
&& GET_CODE (x) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
{
REAL_VALUE_TYPE r;
long i[4];
int endian = WORDS_BIG_ENDIAN ? 1 : 0;
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
switch (GET_MODE_BITSIZE (GET_MODE (x)))
{
case 32:
REAL_VALUE_TO_TARGET_SINGLE (r, i[3 * endian]);
i[1] = 0;
i[2] = 0;
i[3 - 3 * endian] = 0;
break;
case 64:
REAL_VALUE_TO_TARGET_DOUBLE (r, i + 2 * endian);
i[2 - 2 * endian] = 0;
i[3 - 2 * endian] = 0;
break;
case 96:
REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i + endian);
i[3 - 3 * endian] = 0;
break;
case 128:
REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, i);
break;
default:
abort ();
}
#if HOST_BITS_PER_WIDE_INT == 32
return immed_double_const (i[3 * endian], i[1 + endian], mode);
#else
if (HOST_BITS_PER_WIDE_INT != 64)
abort ();
return immed_double_const ((((unsigned long) i[3 * endian])
| ((HOST_WIDE_INT) i[1 + endian] << 32)),
(((unsigned long) i[2 - endian])
| ((HOST_WIDE_INT) i[3 - 3 * endian] << 32)),
mode);
#endif
}
#endif
return 0;
}
rtx
gen_realpart (mode, x)
enum machine_mode mode;
rtx x;
{
if (WORDS_BIG_ENDIAN
&& GET_MODE_BITSIZE (mode) < BITS_PER_WORD
&& REG_P (x)
&& REGNO (x) < FIRST_PSEUDO_REGISTER)
internal_error
("can't access real part of complex value in hard register");
else if (WORDS_BIG_ENDIAN)
return gen_highpart (mode, x);
else
return gen_lowpart (mode, x);
}
rtx
gen_imagpart (mode, x)
enum machine_mode mode;
rtx x;
{
if (WORDS_BIG_ENDIAN)
return gen_lowpart (mode, x);
else if (! WORDS_BIG_ENDIAN
&& GET_MODE_BITSIZE (mode) < BITS_PER_WORD
&& REG_P (x)
&& REGNO (x) < FIRST_PSEUDO_REGISTER)
internal_error
("can't access imaginary part of complex value in hard register");
else
return gen_highpart (mode, x);
}
int
subreg_realpart_p (x)
rtx x;
{
if (GET_CODE (x) != SUBREG)
abort ();
return ((unsigned int) SUBREG_BYTE (x)
< GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x))));
}
rtx
gen_lowpart (mode, x)
enum machine_mode mode;
rtx x;
{
rtx result = gen_lowpart_common (mode, x);
if (result)
return result;
else if (GET_CODE (x) == REG)
{
result = gen_lowpart_common (mode, copy_to_reg (x));
if (result == 0)
abort ();
return result;
}
else if (GET_CODE (x) == MEM)
{
int offset = 0;
if (WORDS_BIG_ENDIAN)
offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
- MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
if (BYTES_BIG_ENDIAN)
offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
- MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
return adjust_address (x, mode, offset);
}
else if (GET_CODE (x) == ADDRESSOF)
return gen_lowpart (mode, force_reg (GET_MODE (x), x));
else
abort ();
}
rtx
gen_highpart (mode, x)
enum machine_mode mode;
rtx x;
{
unsigned int msize = GET_MODE_SIZE (mode);
rtx result;
if (msize > UNITS_PER_WORD
&& msize != GET_MODE_UNIT_SIZE (GET_MODE (x)))
abort ();
result = simplify_gen_subreg (mode, x, GET_MODE (x),
subreg_highpart_offset (mode, GET_MODE (x)));
if (result != NULL_RTX && GET_CODE (result) == MEM)
result = validize_mem (result);
if (!result)
abort ();
return result;
}
rtx
gen_highpart_mode (outermode, innermode, exp)
enum machine_mode outermode, innermode;
rtx exp;
{
if (GET_MODE (exp) != VOIDmode)
{
if (GET_MODE (exp) != innermode)
abort ();
return gen_highpart (outermode, exp);
}
return simplify_gen_subreg (outermode, exp, innermode,
subreg_highpart_offset (outermode, innermode));
}
unsigned int
subreg_lowpart_offset (outermode, innermode)
enum machine_mode outermode, innermode;
{
unsigned int offset = 0;
int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
if (difference > 0)
{
if (WORDS_BIG_ENDIAN)
offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
if (BYTES_BIG_ENDIAN)
offset += difference % UNITS_PER_WORD;
}
return offset;
}
unsigned int
subreg_highpart_offset (outermode, innermode)
enum machine_mode outermode, innermode;
{
unsigned int offset = 0;
int difference = (GET_MODE_SIZE (innermode) - GET_MODE_SIZE (outermode));
if (GET_MODE_SIZE (innermode) < GET_MODE_SIZE (outermode))
abort ();
if (difference > 0)
{
if (! WORDS_BIG_ENDIAN)
offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
if (! BYTES_BIG_ENDIAN)
offset += difference % UNITS_PER_WORD;
}
return offset;
}
int
subreg_lowpart_p (x)
rtx x;
{
if (GET_CODE (x) != SUBREG)
return 1;
else if (GET_MODE (SUBREG_REG (x)) == VOIDmode)
return 0;
return (subreg_lowpart_offset (GET_MODE (x), GET_MODE (SUBREG_REG (x)))
== SUBREG_BYTE (x));
}
rtx
constant_subword (op, offset, mode)
rtx op;
int offset;
enum machine_mode mode;
{
int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD;
HOST_WIDE_INT val;
if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) == UNITS_PER_WORD)
return op;
#ifdef REAL_ARITHMETIC
if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
&& GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_BITSIZE (mode) == 64
&& GET_CODE (op) == CONST_DOUBLE)
{
long k[2];
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
if (BITS_PER_WORD == 32)
{
val = k[offset];
val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
return GEN_INT (val);
}
#if HOST_BITS_PER_WIDE_INT >= 64
else if (BITS_PER_WORD >= 64 && offset == 0)
{
val = k[! WORDS_BIG_ENDIAN];
val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
val |= (HOST_WIDE_INT) k[WORDS_BIG_ENDIAN] & 0xffffffff;
return GEN_INT (val);
}
#endif
else if (BITS_PER_WORD == 16)
{
val = k[offset >> 1];
if ((offset & 1) == ! WORDS_BIG_ENDIAN)
val >>= 16;
val = ((val & 0xffff) ^ 0x8000) - 0x8000;
return GEN_INT (val);
}
else
abort ();
}
else if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
&& GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_BITSIZE (mode) > 64
&& GET_CODE (op) == CONST_DOUBLE)
{
long k[4];
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
if (BITS_PER_WORD == 32)
{
val = k[offset];
val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
return GEN_INT (val);
}
#if HOST_BITS_PER_WIDE_INT >= 64
else if (BITS_PER_WORD >= 64 && offset <= 1)
{
val = k[offset * 2 + ! WORDS_BIG_ENDIAN];
val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
val |= (HOST_WIDE_INT) k[offset * 2 + WORDS_BIG_ENDIAN] & 0xffffffff;
return GEN_INT (val);
}
#endif
else
abort ();
}
#else
if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
|| flag_pretend_float)
&& GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
&& GET_CODE (op) == CONST_DOUBLE)
{
#ifdef HOST_WORDS_BIG_ENDIAN
return GEN_INT (offset == WORDS_BIG_ENDIAN
? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));
#else
return GEN_INT (offset != WORDS_BIG_ENDIAN
? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));
#endif
}
#endif
#ifdef REAL_ARITHMETIC
if (GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_BITSIZE (mode) == 32
&& GET_CODE (op) == CONST_DOUBLE)
{
long l;
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
REAL_VALUE_TO_TARGET_SINGLE (rv, l);
val = l;
val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
if (BITS_PER_WORD == 16)
{
if ((offset & 1) == ! WORDS_BIG_ENDIAN)
val >>= 16;
val = ((val & 0xffff) ^ 0x8000) - 0x8000;
}
return GEN_INT (val);
}
#else
if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
|| flag_pretend_float)
&& sizeof (float) * 8 == HOST_BITS_PER_WIDE_INT
&& GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_SIZE (mode) == UNITS_PER_WORD
&& GET_CODE (op) == CONST_DOUBLE)
{
double d;
union {float f; HOST_WIDE_INT i; } u;
REAL_VALUE_FROM_CONST_DOUBLE (d, op);
u.f = d;
return GEN_INT (u.i);
}
if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
|| flag_pretend_float)
&& sizeof (double) * 8 == HOST_BITS_PER_WIDE_INT
&& GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_SIZE (mode) == UNITS_PER_WORD
&& GET_CODE (op) == CONST_DOUBLE)
{
double d;
union {double d; HOST_WIDE_INT i; } u;
REAL_VALUE_FROM_CONST_DOUBLE (d, op);
u.d = d;
return GEN_INT (u.i);
}
#endif
if (op == const0_rtx)
return op;
if (GET_MODE_CLASS (mode) != MODE_INT
|| (GET_CODE (op) != CONST_INT && GET_CODE (op) != CONST_DOUBLE)
|| BITS_PER_WORD > HOST_BITS_PER_WIDE_INT)
return 0;
if (WORDS_BIG_ENDIAN)
offset = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - offset;
val = (offset / size_ratio == 0
? (GET_CODE (op) == CONST_INT ? INTVAL (op) : CONST_DOUBLE_LOW (op))
: (GET_CODE (op) == CONST_INT
? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op)));
if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT)
val = ((val >> ((offset % size_ratio) * BITS_PER_WORD)));
val = trunc_int_for_mode (val, word_mode);
return GEN_INT (val);
}
rtx
operand_subword (op, offset, validate_address, mode)
rtx op;
unsigned int offset;
int validate_address;
enum machine_mode mode;
{
if (mode == VOIDmode)
mode = GET_MODE (op);
if (mode == VOIDmode)
abort ();
if (mode != BLKmode
&& (GET_MODE_SIZE (mode) < UNITS_PER_WORD))
return 0;
if (mode != BLKmode
&& (offset + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode))
return const0_rtx;
if (GET_CODE (op) == MEM)
{
rtx new = adjust_address_nv (op, word_mode, offset * UNITS_PER_WORD);
if (! validate_address)
return new;
else if (reload_completed)
{
if (! strict_memory_address_p (word_mode, XEXP (new, 0)))
return 0;
}
else
return replace_equiv_address (new, XEXP (new, 0));
}
return simplify_gen_subreg (word_mode, op, mode, (offset * UNITS_PER_WORD));
}
rtx
operand_subword_force (op, offset, mode)
rtx op;
unsigned int offset;
enum machine_mode mode;
{
rtx result = operand_subword (op, offset, 1, mode);
if (result)
return result;
if (mode != BLKmode && mode != VOIDmode)
{
if (GET_CODE (op) == REG)
op = copy_to_reg (op);
else
op = force_reg (mode, op);
}
result = operand_subword (op, offset, 1, mode);
if (result == 0)
abort ();
return result;
}
void
reverse_comparison (insn)
rtx insn;
{
rtx body = PATTERN (insn);
rtx comp;
if (GET_CODE (body) == SET)
comp = SET_SRC (body);
else
comp = SET_SRC (XVECEXP (body, 0, 0));
if (GET_CODE (comp) == COMPARE)
{
rtx op0 = XEXP (comp, 0);
rtx op1 = XEXP (comp, 1);
XEXP (comp, 0) = op1;
XEXP (comp, 1) = op0;
}
else
{
rtx new = gen_rtx_COMPARE (VOIDmode,
CONST0_RTX (GET_MODE (comp)), comp);
if (GET_CODE (body) == SET)
SET_SRC (body) = new;
else
SET_SRC (XVECEXP (body, 0, 0)) = new;
}
}
static tree
component_ref_for_mem_expr (ref)
tree ref;
{
tree inner = TREE_OPERAND (ref, 0);
if (TREE_CODE (inner) == COMPONENT_REF)
inner = component_ref_for_mem_expr (inner);
else
{
tree placeholder_ptr = 0;
while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR
|| TREE_CODE (inner) == NON_LVALUE_EXPR
|| TREE_CODE (inner) == VIEW_CONVERT_EXPR
|| TREE_CODE (inner) == SAVE_EXPR
|| TREE_CODE (inner) == PLACEHOLDER_EXPR)
if (TREE_CODE (inner) == PLACEHOLDER_EXPR)
inner = find_placeholder (inner, &placeholder_ptr);
else
inner = TREE_OPERAND (inner, 0);
if (! DECL_P (inner))
inner = NULL_TREE;
}
if (inner == TREE_OPERAND (ref, 0))
return ref;
else
return build (COMPONENT_REF, TREE_TYPE (ref), inner,
TREE_OPERAND (ref, 1));
}
void
set_mem_attributes (ref, t, objectp)
rtx ref;
tree t;
int objectp;
{
HOST_WIDE_INT alias = MEM_ALIAS_SET (ref);
tree expr = MEM_EXPR (ref);
rtx offset = MEM_OFFSET (ref);
rtx size = MEM_SIZE (ref);
unsigned int align = MEM_ALIGN (ref);
tree type;
if (t == NULL_TREE)
return;
type = TYPE_P (t) ? t : TREE_TYPE (t);
if (DECL_P (t) && ref == DECL_RTL_IF_SET (t))
abort ();
alias = get_alias_set (t);
MEM_VOLATILE_P (ref) = TYPE_VOLATILE (type);
MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type);
RTX_UNCHANGING_P (ref)
|= ((lang_hooks.honor_readonly
&& (TYPE_READONLY (type) || TREE_READONLY (t)))
|| (! TYPE_P (t) && TREE_CONSTANT (t)));
if ((objectp || DECL_P (t)) && ! AGGREGATE_TYPE_P (type))
MEM_SCALAR_P (ref) = 1;
if (objectp || TREE_CODE (t) == INDIRECT_REF || TYPE_ALIGN_OK (type))
align = MAX (align, TYPE_ALIGN (type));
if (TYPE_SIZE_UNIT (type) && host_integerp (TYPE_SIZE_UNIT (type), 1))
size = GEN_INT (tree_low_cst (TYPE_SIZE_UNIT (type), 1));
if (! TYPE_P (t))
{
maybe_set_unchanging (ref, t);
if (TREE_THIS_VOLATILE (t))
MEM_VOLATILE_P (ref) = 1;
while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
|| TREE_CODE (t) == NON_LVALUE_EXPR
|| TREE_CODE (t) == VIEW_CONVERT_EXPR
|| TREE_CODE (t) == SAVE_EXPR)
t = TREE_OPERAND (t, 0);
if (! can_address_p (t))
MEM_KEEP_ALIAS_SET_P (ref) = 1;
if (DECL_P (t))
{
expr = t;
offset = const0_rtx;
size = (DECL_SIZE_UNIT (t)
&& host_integerp (DECL_SIZE_UNIT (t), 1)
? GEN_INT (tree_low_cst (DECL_SIZE_UNIT (t), 1)) : 0);
align = DECL_ALIGN (t);
}
else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
{
align = TYPE_ALIGN (type);
#ifdef CONSTANT_ALIGNMENT
align = CONSTANT_ALIGNMENT (t, align);
#endif
}
else if (TREE_CODE (t) == COMPONENT_REF
&& ! DECL_BIT_FIELD (TREE_OPERAND (t, 1)))
{
expr = component_ref_for_mem_expr (t);
offset = const0_rtx;
}
else if (TREE_CODE (t) == ARRAY_REF)
{
tree off_tree = size_zero_node;
do
{
off_tree
= fold (build (PLUS_EXPR, sizetype,
fold (build (MULT_EXPR, sizetype,
TREE_OPERAND (t, 1),
TYPE_SIZE_UNIT (TREE_TYPE (t)))),
off_tree));
t = TREE_OPERAND (t, 0);
}
while (TREE_CODE (t) == ARRAY_REF);
if (TREE_CODE (t) == COMPONENT_REF)
{
expr = component_ref_for_mem_expr (t);
if (host_integerp (off_tree, 1))
offset = GEN_INT (tree_low_cst (off_tree, 1));
}
}
}
MEM_ATTRS (ref)
= get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref));
if (MEM_IN_STRUCT_P (ref) || MEM_SCALAR_P (ref))
return;
else if (TREE_CODE (t) == COMPONENT_REF || TREE_CODE (t) == ARRAY_REF
|| TREE_CODE (t) == ARRAY_RANGE_REF
|| TREE_CODE (t) == BIT_FIELD_REF)
MEM_IN_STRUCT_P (ref) = 1;
}
void
set_mem_alias_set (mem, set)
rtx mem;
HOST_WIDE_INT set;
{
#ifdef ENABLE_CHECKING
if (!alias_sets_conflict_p (set, MEM_ALIAS_SET (mem)))
abort ();
#endif
MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem),
MEM_SIZE (mem), MEM_ALIGN (mem),
GET_MODE (mem));
}
void
set_mem_align (mem, align)
rtx mem;
unsigned int align;
{
MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem),
MEM_OFFSET (mem), MEM_SIZE (mem), align,
GET_MODE (mem));
}
void
set_mem_expr (mem, expr)
rtx mem;
tree expr;
{
MEM_ATTRS (mem)
= get_mem_attrs (MEM_ALIAS_SET (mem), expr, MEM_OFFSET (mem),
MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem));
}
void
set_mem_offset (mem, offset)
rtx mem, offset;
{
MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem),
offset, MEM_SIZE (mem), MEM_ALIGN (mem),
GET_MODE (mem));
}
static rtx
change_address_1 (memref, mode, addr, validate)
rtx memref;
enum machine_mode mode;
rtx addr;
int validate;
{
rtx new;
if (GET_CODE (memref) != MEM)
abort ();
if (mode == VOIDmode)
mode = GET_MODE (memref);
if (addr == 0)
addr = XEXP (memref, 0);
if (validate)
{
if (reload_in_progress || reload_completed)
{
if (! memory_address_p (mode, addr))
abort ();
}
else
addr = memory_address (mode, addr);
}
if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref))
return memref;
new = gen_rtx_MEM (mode, addr);
MEM_COPY_ATTRIBUTES (new, memref);
return new;
}
rtx
change_address (memref, mode, addr)
rtx memref;
enum machine_mode mode;
rtx addr;
{
rtx new = change_address_1 (memref, mode, addr, 1);
enum machine_mode mmode = GET_MODE (new);
MEM_ATTRS (new)
= get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0,
mmode == BLKmode ? 0 : GEN_INT (GET_MODE_SIZE (mmode)),
(mmode == BLKmode ? BITS_PER_UNIT
: GET_MODE_ALIGNMENT (mmode)),
mmode);
return new;
}
rtx
adjust_address_1 (memref, mode, offset, validate, adjust)
rtx memref;
enum machine_mode mode;
HOST_WIDE_INT offset;
int validate, adjust;
{
rtx addr = XEXP (memref, 0);
rtx new;
rtx memoffset = MEM_OFFSET (memref);
rtx size = 0;
unsigned int memalign = MEM_ALIGN (memref);
addr = copy_rtx (addr);
if (adjust)
{
if (GET_MODE (memref) != BLKmode && GET_CODE (addr) == LO_SUM
&& offset >= 0
&& (unsigned HOST_WIDE_INT) offset
< GET_MODE_ALIGNMENT (GET_MODE (memref)) / BITS_PER_UNIT)
addr = gen_rtx_LO_SUM (Pmode, XEXP (addr, 0),
plus_constant (XEXP (addr, 1), offset));
else
addr = plus_constant (addr, offset);
}
new = change_address_1 (memref, mode, addr, validate);
if (memoffset)
memoffset = GEN_INT (offset + INTVAL (memoffset));
if (offset != 0)
memalign
= MIN (memalign,
(unsigned HOST_WIDE_INT) (offset & -offset) * BITS_PER_UNIT);
if (GET_MODE (new) != BLKmode)
size = GEN_INT (GET_MODE_SIZE (GET_MODE (new)));
else if (MEM_SIZE (memref))
size = plus_constant (MEM_SIZE (memref), -offset);
MEM_ATTRS (new) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref),
memoffset, size, memalign, GET_MODE (new));
return new;
}
rtx
adjust_automodify_address_1 (memref, mode, addr, offset, validate)
rtx memref;
enum machine_mode mode;
rtx addr;
HOST_WIDE_INT offset;
int validate;
{
memref = change_address_1 (memref, VOIDmode, addr, validate);
return adjust_address_1 (memref, mode, offset, validate, 0);
}
rtx
offset_address (memref, offset, pow2)
rtx memref;
rtx offset;
HOST_WIDE_INT pow2;
{
rtx new, addr = XEXP (memref, 0);
new = simplify_gen_binary (PLUS, Pmode, addr, offset);
if (! memory_address_p (GET_MODE (memref), new)
&& GET_CODE (addr) == PLUS
&& XEXP (addr, 0) == pic_offset_table_rtx)
{
addr = force_reg (GET_MODE (addr), addr);
new = simplify_gen_binary (PLUS, Pmode, addr, offset);
}
update_temp_slot_address (XEXP (memref, 0), new);
new = change_address_1 (memref, VOIDmode, new, 1);
MEM_ATTRS (new)
= get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), 0, 0,
MIN (MEM_ALIGN (memref),
(unsigned HOST_WIDE_INT) pow2 * BITS_PER_UNIT),
GET_MODE (new));
return new;
}
rtx
replace_equiv_address (memref, addr)
rtx memref;
rtx addr;
{
update_temp_slot_address (XEXP (memref, 0), addr);
return change_address_1 (memref, VOIDmode, addr, 1);
}
rtx
replace_equiv_address_nv (memref, addr)
rtx memref;
rtx addr;
{
return change_address_1 (memref, VOIDmode, addr, 0);
}
rtx
widen_memory_access (memref, mode, offset)
rtx memref;
enum machine_mode mode;
HOST_WIDE_INT offset;
{
rtx new = adjust_address_1 (memref, mode, offset, 1, 1);
tree expr = MEM_EXPR (new);
rtx memoffset = MEM_OFFSET (new);
unsigned int size = GET_MODE_SIZE (mode);
if (! memoffset)
expr = NULL_TREE;
while (expr)
{
if (TREE_CODE (expr) == COMPONENT_REF)
{
tree field = TREE_OPERAND (expr, 1);
if (! DECL_SIZE_UNIT (field))
{
expr = NULL_TREE;
break;
}
if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST
&& compare_tree_int (DECL_SIZE_UNIT (field), size) >= 0
&& INTVAL (memoffset) >= 0)
break;
if (! host_integerp (DECL_FIELD_OFFSET (field), 1))
{
expr = NULL_TREE;
break;
}
expr = TREE_OPERAND (expr, 0);
memoffset = (GEN_INT (INTVAL (memoffset)
+ tree_low_cst (DECL_FIELD_OFFSET (field), 1)
+ (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
/ BITS_PER_UNIT)));
}
else if (DECL_P (expr)
&& DECL_SIZE_UNIT (expr)
&& compare_tree_int (DECL_SIZE_UNIT (expr), size) >= 0
&& (! memoffset || INTVAL (memoffset) >= 0))
break;
else
{
expr = NULL_TREE;
break;
}
}
if (! expr)
memoffset = NULL_RTX;
MEM_ATTRS (new) = get_mem_attrs (0, expr, memoffset, GEN_INT (size),
MEM_ALIGN (new), mode);
return new;
}
rtx
gen_label_rtx ()
{
rtx label;
label = gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX,
NULL_RTX, label_num++, NULL, NULL);
LABEL_NUSES (label) = 0;
LABEL_ALTERNATE_NAME (label) = NULL;
return label;
}
void
set_new_first_and_last_insn (first, last)
rtx first, last;
{
rtx insn;
first_insn = first;
last_insn = last;
cur_insn_uid = 0;
for (insn = first; insn; insn = NEXT_INSN (insn))
cur_insn_uid = MAX (cur_insn_uid, INSN_UID (insn));
cur_insn_uid++;
}
void
set_new_first_and_last_label_num (first, last)
int first, last;
{
base_label_num = label_num;
first_label_num = first;
last_label_num = last;
}
void
set_new_last_label_num (last)
int last;
{
base_label_num = label_num;
last_label_num = last;
}
void
restore_emit_status (p)
struct function *p ATTRIBUTE_UNUSED;
{
last_label_num = 0;
clear_emit_caches ();
}
void
free_emit_status (f)
struct function *f;
{
PFE_FREE (f->emit->x_regno_reg_rtx);
PFE_FREE (f->emit->regno_pointer_align);
PFE_FREE (f->emit->regno_decl);
PFE_FREE (f->emit);
f->emit = NULL;
}
void
unshare_all_rtl (fndecl, insn)
tree fndecl;
rtx insn;
{
tree decl;
for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
SET_DECL_RTL (decl, copy_rtx_if_shared (DECL_RTL (decl)));
unshare_all_decls (DECL_INITIAL (fndecl));
unshare_all_rtl_1 (insn);
stack_slot_list = copy_rtx_if_shared (stack_slot_list);
}
void
unshare_all_rtl_again (insn)
rtx insn;
{
rtx p;
tree decl;
for (p = insn; p; p = NEXT_INSN (p))
if (INSN_P (p))
{
reset_used_flags (PATTERN (p));
reset_used_flags (REG_NOTES (p));
reset_used_flags (LOG_LINKS (p));
}
reset_used_decls (DECL_INITIAL (cfun->decl));
for (decl = DECL_ARGUMENTS (cfun->decl); decl; decl = TREE_CHAIN (decl))
reset_used_flags (DECL_RTL (decl));
reset_used_flags (stack_slot_list);
unshare_all_rtl (cfun->decl, insn);
}
static void
unshare_all_rtl_1 (insn)
rtx insn;
{
for (; insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn));
LOG_LINKS (insn) = copy_rtx_if_shared (LOG_LINKS (insn));
}
}
static void
unshare_all_decls (blk)
tree blk;
{
tree t;
for (t = BLOCK_VARS (blk); t; t = TREE_CHAIN (t))
if (DECL_RTL_SET_P (t))
SET_DECL_RTL (t, copy_rtx_if_shared (DECL_RTL (t)));
for (t = BLOCK_SUBBLOCKS (blk); t; t = TREE_CHAIN (t))
unshare_all_decls (t);
}
static void
reset_used_decls (blk)
tree blk;
{
tree t;
for (t = BLOCK_VARS (blk); t; t = TREE_CHAIN (t))
if (DECL_RTL_SET_P (t))
reset_used_flags (DECL_RTL (t));
for (t = BLOCK_SUBBLOCKS (blk); t; t = TREE_CHAIN (t))
reset_used_decls (t);
}
rtx
copy_most_rtx (orig, may_share)
rtx orig;
rtx may_share;
{
rtx copy;
int i, j;
RTX_CODE code;
const char *format_ptr;
if (orig == may_share
|| (GET_CODE (may_share) == EXPR_LIST
&& in_expr_list_p (may_share, orig)))
return orig;
code = GET_CODE (orig);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
return orig;
default:
break;
}
copy = rtx_alloc (code);
PUT_MODE (copy, GET_MODE (orig));
copy->in_struct = orig->in_struct;
copy->volatil = orig->volatil;
copy->unchanging = orig->unchanging;
copy->integrated = orig->integrated;
copy->frame_related = orig->frame_related;
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
switch (*format_ptr++)
{
case 'e':
XEXP (copy, i) = XEXP (orig, i);
if (XEXP (orig, i) != NULL && XEXP (orig, i) != may_share)
XEXP (copy, i) = copy_most_rtx (XEXP (orig, i), may_share);
break;
case 'u':
XEXP (copy, i) = XEXP (orig, i);
break;
case 'E':
case 'V':
XVEC (copy, i) = XVEC (orig, i);
if (XVEC (orig, i) != NULL)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
XVECEXP (copy, i, j)
= copy_most_rtx (XVECEXP (orig, i, j), may_share);
}
break;
case 'w':
XWINT (copy, i) = XWINT (orig, i);
break;
case 'n':
case 'i':
XINT (copy, i) = XINT (orig, i);
break;
case 't':
XTREE (copy, i) = XTREE (orig, i);
break;
case 's':
case 'S':
XSTR (copy, i) = XSTR (orig, i);
break;
case '0':
X0WINT (copy, i) = X0WINT (orig, i);
break;
default:
abort ();
}
}
return copy;
}
rtx
copy_rtx_if_shared (orig)
rtx orig;
{
rtx x = orig;
int i;
enum rtx_code code;
const char *format_ptr;
int copied = 0;
if (x == 0)
return 0;
code = GET_CODE (x);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
case SCRATCH:
return x;
case CONST:
if (GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
return x;
break;
case INSN:
case JUMP_INSN:
case CALL_INSN:
case NOTE:
case BARRIER:
return x;
case MEM:
if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
return x;
break;
default:
break;
}
if (x->used)
{
rtx copy;
copy = rtx_alloc (code);
memcpy (copy, x,
(sizeof (*copy) - sizeof (copy->fld)
+ sizeof (copy->fld[0]) * GET_RTX_LENGTH (code)));
x = copy;
copied = 1;
}
x->used = 1;
format_ptr = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++)
{
switch (*format_ptr++)
{
case 'e':
XEXP (x, i) = copy_rtx_if_shared (XEXP (x, i));
break;
case 'E':
if (XVEC (x, i) != NULL)
{
int j;
int len = XVECLEN (x, i);
if (copied && len > 0)
XVEC (x, i) = gen_rtvec_v (len, XVEC (x, i)->elem);
for (j = 0; j < len; j++)
XVECEXP (x, i, j) = copy_rtx_if_shared (XVECEXP (x, i, j));
}
break;
}
}
return x;
}
void
reset_used_flags (x)
rtx x;
{
int i, j;
enum rtx_code code;
const char *format_ptr;
if (x == 0)
return;
code = GET_CODE (x);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
return;
case INSN:
case JUMP_INSN:
case CALL_INSN:
case NOTE:
case LABEL_REF:
case BARRIER:
return;
default:
break;
}
x->used = 0;
format_ptr = GET_RTX_FORMAT (code);
for (i = 0; i < GET_RTX_LENGTH (code); i++)
{
switch (*format_ptr++)
{
case 'e':
reset_used_flags (XEXP (x, i));
break;
case 'E':
for (j = 0; j < XVECLEN (x, i); j++)
reset_used_flags (XVECEXP (x, i, j));
break;
}
}
}
rtx
make_safe_from (x, other)
rtx x, other;
{
while (1)
switch (GET_CODE (other))
{
case SUBREG:
other = SUBREG_REG (other);
break;
case STRICT_LOW_PART:
case SIGN_EXTEND:
case ZERO_EXTEND:
other = XEXP (other, 0);
break;
default:
goto done;
}
done:
if ((GET_CODE (other) == MEM
&& ! CONSTANT_P (x)
&& GET_CODE (x) != REG
&& GET_CODE (x) != SUBREG)
|| (GET_CODE (other) == REG
&& (REGNO (other) < FIRST_PSEUDO_REGISTER
|| reg_mentioned_p (other, x))))
{
rtx temp = gen_reg_rtx (GET_MODE (x));
emit_move_insn (temp, x);
return temp;
}
return x;
}
rtx
get_insns ()
{
return first_insn;
}
rtx
get_last_insn ()
{
return last_insn;
}
void
set_last_insn (insn)
rtx insn;
{
if (NEXT_INSN (insn) != 0)
abort ();
last_insn = insn;
}
rtx
get_last_insn_anywhere ()
{
struct sequence_stack *stack;
if (last_insn)
return last_insn;
for (stack = seq_stack; stack; stack = stack->next)
if (stack->last != 0)
return stack->last;
return 0;
}
int
get_max_uid ()
{
return cur_insn_uid;
}
void
renumber_insns (stream)
FILE *stream;
{
rtx insn;
if (!flag_renumber_insns)
return;
if (flag_renumber_insns == 1 && get_max_uid () < 25000)
return;
cur_insn_uid = 1;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
if (stream)
fprintf (stream, "Renumbering insn %d to %d\n",
INSN_UID (insn), cur_insn_uid);
INSN_UID (insn) = cur_insn_uid++;
}
}
rtx
next_insn (insn)
rtx insn;
{
if (insn)
{
insn = NEXT_INSN (insn);
if (insn && GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0, 0);
}
return insn;
}
rtx
previous_insn (insn)
rtx insn;
{
if (insn)
{
insn = PREV_INSN (insn);
if (insn && GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0, XVECLEN (PATTERN (insn), 0) - 1);
}
return insn;
}
rtx
next_nonnote_insn (insn)
rtx insn;
{
while (insn)
{
insn = NEXT_INSN (insn);
if (insn == 0 || GET_CODE (insn) != NOTE)
break;
}
return insn;
}
rtx
prev_nonnote_insn (insn)
rtx insn;
{
while (insn)
{
insn = PREV_INSN (insn);
if (insn == 0 || GET_CODE (insn) != NOTE)
break;
}
return insn;
}
rtx
next_real_insn (insn)
rtx insn;
{
while (insn)
{
insn = NEXT_INSN (insn);
if (insn == 0 || GET_CODE (insn) == INSN
|| GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
break;
}
return insn;
}
rtx
prev_real_insn (insn)
rtx insn;
{
while (insn)
{
insn = PREV_INSN (insn);
if (insn == 0 || GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN
|| GET_CODE (insn) == JUMP_INSN)
break;
}
return insn;
}
int
active_insn_p (insn)
rtx insn;
{
return (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
|| (GET_CODE (insn) == INSN
&& (! reload_completed
|| (GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER))));
}
rtx
next_active_insn (insn)
rtx insn;
{
while (insn)
{
insn = NEXT_INSN (insn);
if (insn == 0 || active_insn_p (insn))
break;
}
return insn;
}
rtx
prev_active_insn (insn)
rtx insn;
{
while (insn)
{
insn = PREV_INSN (insn);
if (insn == 0 || active_insn_p (insn))
break;
}
return insn;
}
rtx
next_label (insn)
rtx insn;
{
while (insn)
{
insn = NEXT_INSN (insn);
if (insn == 0 || GET_CODE (insn) == CODE_LABEL)
break;
}
return insn;
}
rtx
prev_label (insn)
rtx insn;
{
while (insn)
{
insn = PREV_INSN (insn);
if (insn == 0 || GET_CODE (insn) == CODE_LABEL)
break;
}
return insn;
}
#ifdef HAVE_cc0
void
link_cc0_insns (insn)
rtx insn;
{
rtx user = next_nonnote_insn (insn);
if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE)
user = XVECEXP (PATTERN (user), 0, 0);
REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn,
REG_NOTES (user));
REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_CC_USER, user, REG_NOTES (insn));
}
rtx
next_cc0_user (insn)
rtx insn;
{
rtx note = find_reg_note (insn, REG_CC_USER, NULL_RTX);
if (note)
return XEXP (note, 0);
insn = next_nonnote_insn (insn);
if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0, 0);
if (insn && INSN_P (insn) && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
return insn;
return 0;
}
rtx
prev_cc0_setter (insn)
rtx insn;
{
rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
if (note)
return XEXP (note, 0);
insn = prev_nonnote_insn (insn);
if (! sets_cc0_p (PATTERN (insn)))
abort ();
return insn;
}
#endif
static void
mark_label_nuses(x)
rtx x;
{
enum rtx_code code;
int i, j;
const char *fmt;
code = GET_CODE (x);
if (code == LABEL_REF)
LABEL_NUSES (XEXP (x, 0))++;
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
mark_label_nuses (XEXP (x, i));
else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
mark_label_nuses (XVECEXP (x, i, j));
}
}
rtx
try_split (pat, trial, last)
rtx pat, trial;
int last;
{
rtx before = PREV_INSN (trial);
rtx after = NEXT_INSN (trial);
int has_barrier = 0;
rtx tem;
rtx note, seq;
int probability;
if (any_condjump_p (trial)
&& (note = find_reg_note (trial, REG_BR_PROB, 0)))
split_branch_probability = INTVAL (XEXP (note, 0));
probability = split_branch_probability;
seq = split_insns (pat, trial);
split_branch_probability = -1;
if (after && GET_CODE (after) == BARRIER)
{
has_barrier = 1;
after = NEXT_INSN (after);
}
if (seq)
{
if (GET_CODE (seq) == SEQUENCE)
{
int i, njumps = 0;
for (i = 0; i < XVECLEN (seq, 0); i++)
if (GET_CODE (XVECEXP (seq, 0, i)) == INSN
&& rtx_equal_p (PATTERN (XVECEXP (seq, 0, i)), pat))
return trial;
for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (seq, 0, i)) == JUMP_INSN)
{
rtx insn = XVECEXP (seq, 0, i);
mark_jump_label (PATTERN (insn),
XVECEXP (seq, 0, i), 0);
njumps++;
if (probability != -1
&& any_condjump_p (insn)
&& !find_reg_note (insn, REG_BR_PROB, 0))
{
if (njumps != 1)
abort ();
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_BR_PROB,
GEN_INT (probability),
REG_NOTES (insn));
}
}
if (GET_CODE (trial) == CALL_INSN)
for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (seq, 0, i)) == CALL_INSN)
CALL_INSN_FUNCTION_USAGE (XVECEXP (seq, 0, i))
= CALL_INSN_FUNCTION_USAGE (trial);
for (note = REG_NOTES (trial); note ; note = XEXP (note, 1))
{
switch (REG_NOTE_KIND (note))
{
case REG_EH_REGION:
for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
{
rtx insn = XVECEXP (seq, 0, i);
if (GET_CODE (insn) == CALL_INSN
|| (flag_non_call_exceptions
&& may_trap_p (PATTERN (insn))))
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_EH_REGION,
XEXP (note, 0),
REG_NOTES (insn));
}
break;
case REG_NORETURN:
case REG_SETJMP:
case REG_ALWAYS_RETURN:
for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
{
rtx insn = XVECEXP (seq, 0, i);
if (GET_CODE (insn) == CALL_INSN)
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
XEXP (note, 0),
REG_NOTES (insn));
}
break;
case REG_NON_LOCAL_GOTO:
for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
{
rtx insn = XVECEXP (seq, 0, i);
if (GET_CODE (insn) == JUMP_INSN)
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
XEXP (note, 0),
REG_NOTES (insn));
}
break;
default:
break;
}
}
if (GET_CODE (trial) == INSN)
for (i = XVECLEN (seq, 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (seq, 0, i)) == INSN)
mark_label_nuses (PATTERN (XVECEXP (seq, 0, i)));
tem = emit_insn_after (seq, trial);
delete_related_insns (trial);
if (has_barrier)
emit_barrier_after (tem);
for (tem = NEXT_INSN (before); tem != after; tem = NEXT_INSN (tem))
if (! INSN_DELETED_P (tem) && INSN_P (tem))
tem = try_split (PATTERN (tem), tem, 1);
}
else if (rtx_equal_p (seq, pat))
return trial;
else
{
PATTERN (trial) = seq;
INSN_CODE (trial) = -1;
try_split (seq, trial, last);
}
return last
? (after ? PREV_INSN (after) : last_insn)
: NEXT_INSN (before);
}
return trial;
}
rtx
make_insn_raw (pattern)
rtx pattern;
{
rtx insn;
insn = rtx_alloc (INSN);
INSN_UID (insn) = cur_insn_uid++;
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
#ifdef ENABLE_RTL_CHECKING
if (insn
&& INSN_P (insn)
&& (returnjump_p (insn)
|| (GET_CODE (insn) == SET
&& SET_DEST (insn) == pc_rtx)))
{
warning ("ICE: emit_insn used where emit_jump_insn needed:\n");
debug_rtx (insn);
}
#endif
return insn;
}
static rtx
make_jump_insn_raw (pattern)
rtx pattern;
{
rtx insn;
insn = rtx_alloc (JUMP_INSN);
INSN_UID (insn) = cur_insn_uid++;
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
JUMP_LABEL (insn) = NULL;
return insn;
}
static rtx
make_call_insn_raw (pattern)
rtx pattern;
{
rtx insn;
insn = rtx_alloc (CALL_INSN);
INSN_UID (insn) = cur_insn_uid++;
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
LOG_LINKS (insn) = NULL;
REG_NOTES (insn) = NULL;
CALL_INSN_FUNCTION_USAGE (insn) = NULL;
return insn;
}
void
add_insn (insn)
rtx insn;
{
PREV_INSN (insn) = last_insn;
NEXT_INSN (insn) = 0;
if (NULL != last_insn)
NEXT_INSN (last_insn) = insn;
if (NULL == first_insn)
first_insn = insn;
last_insn = insn;
}
void
add_insn_after (insn, after)
rtx insn, after;
{
rtx next = NEXT_INSN (after);
basic_block bb;
if (optimize && INSN_DELETED_P (after))
abort ();
NEXT_INSN (insn) = next;
PREV_INSN (insn) = after;
if (next)
{
PREV_INSN (next) = insn;
if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE)
PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = insn;
}
else if (last_insn == after)
last_insn = insn;
else
{
struct sequence_stack *stack = seq_stack;
for (; stack; stack = stack->next)
if (after == stack->last)
{
stack->last = insn;
break;
}
if (stack == 0)
abort ();
}
if (basic_block_for_insn
&& (unsigned int) INSN_UID (after) < basic_block_for_insn->num_elements
&& (bb = BLOCK_FOR_INSN (after)))
{
set_block_for_insn (insn, bb);
if (bb->end == after
&& GET_CODE (insn) != BARRIER
&& (GET_CODE (insn) != NOTE
|| NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK))
bb->end = insn;
}
NEXT_INSN (after) = insn;
if (GET_CODE (after) == INSN && GET_CODE (PATTERN (after)) == SEQUENCE)
{
rtx sequence = PATTERN (after);
NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn;
}
}
void
add_insn_before (insn, before)
rtx insn, before;
{
rtx prev = PREV_INSN (before);
basic_block bb;
if (optimize && INSN_DELETED_P (before))
abort ();
PREV_INSN (insn) = prev;
NEXT_INSN (insn) = before;
if (prev)
{
NEXT_INSN (prev) = insn;
if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE)
{
rtx sequence = PATTERN (prev);
NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = insn;
}
}
else if (first_insn == before)
first_insn = insn;
else
{
struct sequence_stack *stack = seq_stack;
for (; stack; stack = stack->next)
if (before == stack->first)
{
stack->first = insn;
break;
}
if (stack == 0)
abort ();
}
if (basic_block_for_insn
&& (unsigned int) INSN_UID (before) < basic_block_for_insn->num_elements
&& (bb = BLOCK_FOR_INSN (before)))
{
set_block_for_insn (insn, bb);
if (bb->head == insn
&& GET_CODE (insn) != BARRIER
&& (GET_CODE (insn) != NOTE
|| NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK))
abort ();
}
PREV_INSN (before) = insn;
if (GET_CODE (before) == INSN && GET_CODE (PATTERN (before)) == SEQUENCE)
PREV_INSN (XVECEXP (PATTERN (before), 0, 0)) = insn;
}
void
remove_insn (insn)
rtx insn;
{
rtx next = NEXT_INSN (insn);
rtx prev = PREV_INSN (insn);
basic_block bb;
if (prev)
{
NEXT_INSN (prev) = next;
if (GET_CODE (prev) == INSN && GET_CODE (PATTERN (prev)) == SEQUENCE)
{
rtx sequence = PATTERN (prev);
NEXT_INSN (XVECEXP (sequence, 0, XVECLEN (sequence, 0) - 1)) = next;
}
}
else if (first_insn == insn)
first_insn = next;
else
{
struct sequence_stack *stack = seq_stack;
for (; stack; stack = stack->next)
if (insn == stack->first)
{
stack->first = next;
break;
}
if (stack == 0)
abort ();
}
if (next)
{
PREV_INSN (next) = prev;
if (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == SEQUENCE)
PREV_INSN (XVECEXP (PATTERN (next), 0, 0)) = prev;
}
else if (last_insn == insn)
last_insn = prev;
else
{
struct sequence_stack *stack = seq_stack;
for (; stack; stack = stack->next)
if (insn == stack->last)
{
stack->last = prev;
break;
}
if (stack == 0)
abort ();
}
if (basic_block_for_insn
&& (unsigned int) INSN_UID (insn) < basic_block_for_insn->num_elements
&& (bb = BLOCK_FOR_INSN (insn)))
{
if (bb->head == insn)
{
if (GET_CODE (insn) == NOTE)
abort ();
bb->head = next;
}
if (bb->end == insn)
bb->end = prev;
}
}
void
delete_insns_since (from)
rtx from;
{
if (from == 0)
first_insn = 0;
else
NEXT_INSN (from) = 0;
last_insn = from;
}
void
reorder_insns_nobb (from, to, after)
rtx from, to, after;
{
if (PREV_INSN (from))
NEXT_INSN (PREV_INSN (from)) = NEXT_INSN (to);
if (NEXT_INSN (to))
PREV_INSN (NEXT_INSN (to)) = PREV_INSN (from);
if (last_insn == to)
last_insn = PREV_INSN (from);
if (first_insn == from)
first_insn = NEXT_INSN (to);
if (NEXT_INSN (after))
PREV_INSN (NEXT_INSN (after)) = to;
NEXT_INSN (to) = NEXT_INSN (after);
PREV_INSN (from) = after;
NEXT_INSN (after) = from;
if (after == last_insn)
last_insn = to;
}
void
reorder_insns (from, to, after)
rtx from, to, after;
{
rtx prev = PREV_INSN (from);
basic_block bb, bb2;
reorder_insns_nobb (from, to, after);
if (basic_block_for_insn
&& (unsigned int) INSN_UID (after) < basic_block_for_insn->num_elements
&& (bb = BLOCK_FOR_INSN (after)))
{
rtx x;
if (basic_block_for_insn
&& ((unsigned int) INSN_UID (from)
< basic_block_for_insn->num_elements)
&& (bb2 = BLOCK_FOR_INSN (from)))
{
if (bb2->end == to)
bb2->end = prev;
}
if (bb->end == after)
bb->end = to;
for (x = from; x != NEXT_INSN (to); x = NEXT_INSN (x))
set_block_for_insn (x, bb);
}
}
static rtx
find_line_note (insn)
rtx insn;
{
if (no_line_numbers)
return 0;
for (; insn; insn = PREV_INSN (insn))
if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) >= 0)
break;
return insn;
}
void
reorder_insns_with_line_notes (from, to, after)
rtx from, to, after;
{
rtx from_line = find_line_note (from);
rtx after_line = find_line_note (after);
reorder_insns (from, to, after);
if (from_line == after_line)
return;
if (from_line)
emit_line_note_after (NOTE_SOURCE_FILE (from_line),
NOTE_LINE_NUMBER (from_line),
after);
if (after_line)
emit_line_note_after (NOTE_SOURCE_FILE (after_line),
NOTE_LINE_NUMBER (after_line),
to);
}
void
remove_unnecessary_notes ()
{
rtx block_stack = NULL_RTX;
rtx eh_stack = NULL_RTX;
rtx insn;
rtx next;
rtx tmp;
for (insn = NEXT_INSN (get_insns ()); insn; insn = next)
{
next = NEXT_INSN (insn);
if (GET_CODE (insn) != NOTE)
continue;
switch (NOTE_LINE_NUMBER (insn))
{
case NOTE_INSN_DELETED:
case NOTE_INSN_LOOP_END_TOP_COND:
remove_insn (insn);
break;
case NOTE_INSN_EH_REGION_BEG:
eh_stack = alloc_INSN_LIST (insn, eh_stack);
break;
case NOTE_INSN_EH_REGION_END:
if (eh_stack == NULL_RTX)
abort ();
if (NOTE_EH_HANDLER (XEXP (eh_stack, 0)) != NOTE_EH_HANDLER (insn))
abort ();
tmp = eh_stack;
eh_stack = XEXP (eh_stack, 1);
free_INSN_LIST_node (tmp);
break;
case NOTE_INSN_BLOCK_BEG:
if (NOTE_BLOCK (insn) == NULL_TREE)
abort ();
block_stack = alloc_INSN_LIST (insn, block_stack);
break;
case NOTE_INSN_BLOCK_END:
if (block_stack == NULL_RTX)
abort ();
if (NOTE_BLOCK (XEXP (block_stack, 0)) != NOTE_BLOCK (insn))
abort ();
tmp = block_stack;
block_stack = XEXP (block_stack, 1);
free_INSN_LIST_node (tmp);
for (tmp = PREV_INSN (insn); tmp ; tmp = PREV_INSN (tmp))
{
if (INSN_P (tmp))
break;
if (GET_CODE (tmp) != NOTE)
continue;
if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_BEG)
{
if (! is_body_block (NOTE_BLOCK (insn))
&& (*debug_hooks->ignore_block) (NOTE_BLOCK (insn)))
{
remove_insn (tmp);
remove_insn (insn);
}
break;
}
else if (NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BLOCK_END)
break;
}
}
}
if (block_stack || eh_stack)
abort ();
}
rtx
emit_insn_before (pattern, before)
rtx pattern, before;
{
rtx insn = before;
if (GET_CODE (pattern) == SEQUENCE)
{
int i;
for (i = 0; i < XVECLEN (pattern, 0); i++)
{
insn = XVECEXP (pattern, 0, i);
add_insn_before (insn, before);
}
}
else
{
insn = make_insn_raw (pattern);
add_insn_before (insn, before);
}
return insn;
}
rtx
emit_jump_insn_before (pattern, before)
rtx pattern, before;
{
rtx insn;
if (GET_CODE (pattern) == SEQUENCE)
insn = emit_insn_before (pattern, before);
else
{
insn = make_jump_insn_raw (pattern);
add_insn_before (insn, before);
}
return insn;
}
rtx
emit_call_insn_before (pattern, before)
rtx pattern, before;
{
rtx insn;
if (GET_CODE (pattern) == SEQUENCE)
insn = emit_insn_before (pattern, before);
else
{
insn = make_call_insn_raw (pattern);
add_insn_before (insn, before);
PUT_CODE (insn, CALL_INSN);
}
return insn;
}
rtx
emit_barrier_before (before)
rtx before;
{
rtx insn = rtx_alloc (BARRIER);
INSN_UID (insn) = cur_insn_uid++;
add_insn_before (insn, before);
return insn;
}
rtx
emit_label_before (label, before)
rtx label, before;
{
if (INSN_UID (label) == 0)
{
INSN_UID (label) = cur_insn_uid++;
add_insn_before (label, before);
}
return label;
}
rtx
emit_note_before (subtype, before)
int subtype;
rtx before;
{
rtx note = rtx_alloc (NOTE);
INSN_UID (note) = cur_insn_uid++;
NOTE_SOURCE_FILE (note) = 0;
NOTE_LINE_NUMBER (note) = subtype;
add_insn_before (note, before);
return note;
}
rtx
emit_insn_after (pattern, after)
rtx pattern, after;
{
rtx insn = after;
if (GET_CODE (pattern) == SEQUENCE)
{
int i;
for (i = 0; i < XVECLEN (pattern, 0); i++)
{
insn = XVECEXP (pattern, 0, i);
add_insn_after (insn, after);
after = insn;
}
}
else
{
insn = make_insn_raw (pattern);
add_insn_after (insn, after);
}
return insn;
}
void
emit_insn_after_with_line_notes (pattern, after, from)
rtx pattern, after, from;
{
rtx from_line = find_line_note (from);
rtx after_line = find_line_note (after);
rtx insn = emit_insn_after (pattern, after);
if (from_line)
emit_line_note_after (NOTE_SOURCE_FILE (from_line),
NOTE_LINE_NUMBER (from_line),
after);
if (after_line)
emit_line_note_after (NOTE_SOURCE_FILE (after_line),
NOTE_LINE_NUMBER (after_line),
insn);
}
rtx
emit_jump_insn_after (pattern, after)
rtx pattern, after;
{
rtx insn;
if (GET_CODE (pattern) == SEQUENCE)
insn = emit_insn_after (pattern, after);
else
{
insn = make_jump_insn_raw (pattern);
add_insn_after (insn, after);
}
return insn;
}
rtx
emit_barrier_after (after)
rtx after;
{
rtx insn = rtx_alloc (BARRIER);
INSN_UID (insn) = cur_insn_uid++;
add_insn_after (insn, after);
return insn;
}
rtx
emit_label_after (label, after)
rtx label, after;
{
if (INSN_UID (label) == 0)
{
INSN_UID (label) = cur_insn_uid++;
add_insn_after (label, after);
}
return label;
}
rtx
emit_note_after (subtype, after)
int subtype;
rtx after;
{
rtx note = rtx_alloc (NOTE);
INSN_UID (note) = cur_insn_uid++;
NOTE_SOURCE_FILE (note) = 0;
NOTE_LINE_NUMBER (note) = subtype;
add_insn_after (note, after);
return note;
}
rtx
emit_line_note_after (file, line, after)
const char *file;
int line;
rtx after;
{
rtx note;
if (no_line_numbers && line > 0)
{
cur_insn_uid++;
return 0;
}
note = rtx_alloc (NOTE);
INSN_UID (note) = cur_insn_uid++;
NOTE_SOURCE_FILE (note) = file;
NOTE_LINE_NUMBER (note) = line;
add_insn_after (note, after);
return note;
}
rtx
emit_insn (pattern)
rtx pattern;
{
rtx insn = last_insn;
if (GET_CODE (pattern) == SEQUENCE)
{
int i;
for (i = 0; i < XVECLEN (pattern, 0); i++)
{
insn = XVECEXP (pattern, 0, i);
add_insn (insn);
}
}
else
{
insn = make_insn_raw (pattern);
add_insn (insn);
}
return insn;
}
rtx
emit_insns (insn)
rtx insn;
{
rtx last = 0;
while (insn)
{
rtx next = NEXT_INSN (insn);
add_insn (insn);
last = insn;
insn = next;
}
return last;
}
rtx
emit_insns_before (insn, before)
rtx insn;
rtx before;
{
rtx last = 0;
while (insn)
{
rtx next = NEXT_INSN (insn);
add_insn_before (insn, before);
last = insn;
insn = next;
}
return last;
}
rtx
emit_insns_after (first, after)
rtx first;
rtx after;
{
rtx last;
rtx after_after;
basic_block bb;
if (!after)
abort ();
if (!first)
return after;
if (basic_block_for_insn
&& (unsigned int) INSN_UID (after) < basic_block_for_insn->num_elements
&& (bb = BLOCK_FOR_INSN (after)))
{
for (last = first; NEXT_INSN (last); last = NEXT_INSN (last))
set_block_for_insn (last, bb);
set_block_for_insn (last, bb);
if (bb->end == after)
bb->end = last;
}
else
for (last = first; NEXT_INSN (last); last = NEXT_INSN (last))
continue;
after_after = NEXT_INSN (after);
NEXT_INSN (after) = first;
PREV_INSN (first) = after;
NEXT_INSN (last) = after_after;
if (after_after)
PREV_INSN (after_after) = last;
if (after == last_insn)
last_insn = last;
return last;
}
rtx
emit_jump_insn (pattern)
rtx pattern;
{
if (GET_CODE (pattern) == SEQUENCE)
return emit_insn (pattern);
else
{
rtx insn = make_jump_insn_raw (pattern);
add_insn (insn);
return insn;
}
}
rtx
emit_call_insn (pattern)
rtx pattern;
{
if (GET_CODE (pattern) == SEQUENCE)
return emit_insn (pattern);
else
{
rtx insn = make_call_insn_raw (pattern);
add_insn (insn);
PUT_CODE (insn, CALL_INSN);
return insn;
}
}
rtx
emit_label (label)
rtx label;
{
if (INSN_UID (label) == 0)
{
INSN_UID (label) = cur_insn_uid++;
add_insn (label);
}
return label;
}
rtx
emit_barrier ()
{
rtx barrier = rtx_alloc (BARRIER);
INSN_UID (barrier) = cur_insn_uid++;
add_insn (barrier);
return barrier;
}
rtx
emit_line_note (file, line)
const char *file;
int line;
{
set_file_and_line_for_stmt (file, line);
#if 0
if (no_line_numbers)
return 0;
#endif
return emit_note (file, line);
}
rtx
emit_note (file, line)
const char *file;
int line;
{
rtx note;
if (line > 0)
{
if (file && last_filename && !strcmp (file, last_filename)
&& line == last_linenum)
return 0;
last_filename = file;
last_linenum = line;
}
if (no_line_numbers && line > 0)
{
cur_insn_uid++;
return 0;
}
note = rtx_alloc (NOTE);
INSN_UID (note) = cur_insn_uid++;
NOTE_SOURCE_FILE (note) = file;
NOTE_LINE_NUMBER (note) = line;
add_insn (note);
return note;
}
rtx
emit_line_note_force (file, line)
const char *file;
int line;
{
last_linenum = -1;
return emit_line_note (file, line);
}
void
force_next_line_note ()
{
last_linenum = -1;
}
rtx
set_unique_reg_note (insn, kind, datum)
rtx insn;
enum reg_note kind;
rtx datum;
{
rtx note = find_reg_note (insn, kind, NULL_RTX);
switch (kind)
{
case REG_EQUAL:
case REG_EQUIV:
if (GET_CODE (PATTERN (insn)) == PARALLEL && multiple_sets (insn))
{
if (note)
abort ();
return NULL_RTX;
}
if (GET_CODE (datum) == ASM_OPERANDS)
return NULL_RTX;
break;
default:
break;
}
if (note)
{
XEXP (note, 0) = datum;
return note;
}
REG_NOTES (insn) = gen_rtx_EXPR_LIST (kind, datum, REG_NOTES (insn));
return REG_NOTES (insn);
}
enum rtx_code
classify_insn (x)
rtx x;
{
if (GET_CODE (x) == CODE_LABEL)
return CODE_LABEL;
if (GET_CODE (x) == CALL)
return CALL_INSN;
if (GET_CODE (x) == RETURN)
return JUMP_INSN;
if (GET_CODE (x) == SET)
{
if (SET_DEST (x) == pc_rtx)
return JUMP_INSN;
else if (GET_CODE (SET_SRC (x)) == CALL)
return CALL_INSN;
else
return INSN;
}
if (GET_CODE (x) == PARALLEL)
{
int j;
for (j = XVECLEN (x, 0) - 1; j >= 0; j--)
if (GET_CODE (XVECEXP (x, 0, j)) == CALL)
return CALL_INSN;
else if (GET_CODE (XVECEXP (x, 0, j)) == SET
&& SET_DEST (XVECEXP (x, 0, j)) == pc_rtx)
return JUMP_INSN;
else if (GET_CODE (XVECEXP (x, 0, j)) == SET
&& GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == CALL)
return CALL_INSN;
}
return INSN;
}
rtx
emit (x)
rtx x;
{
enum rtx_code code = classify_insn (x);
if (code == CODE_LABEL)
return emit_label (x);
else if (code == INSN)
return emit_insn (x);
else if (code == JUMP_INSN)
{
rtx insn = emit_jump_insn (x);
if (any_uncondjump_p (insn) || GET_CODE (x) == RETURN)
return emit_barrier ();
return insn;
}
else if (code == CALL_INSN)
return emit_call_insn (x);
else
abort ();
}
void
start_sequence ()
{
struct sequence_stack *tem;
tem = (struct sequence_stack *)
PFE_MALLOC (sizeof (struct sequence_stack), PFE_ALLOC_SEQUENCE_STACK);
tem->next = seq_stack;
tem->first = first_insn;
tem->last = last_insn;
tem->sequence_rtl_expr = seq_rtl_expr;
seq_stack = tem;
first_insn = 0;
last_insn = 0;
}
void
start_sequence_for_rtl_expr (t)
tree t;
{
start_sequence ();
seq_rtl_expr = t;
}
void
push_to_sequence (first)
rtx first;
{
rtx last;
start_sequence ();
for (last = first; last && NEXT_INSN (last); last = NEXT_INSN (last));
first_insn = first;
last_insn = last;
}
void
push_to_full_sequence (first, last)
rtx first, last;
{
start_sequence ();
first_insn = first;
last_insn = last;
if (last && NEXT_INSN (last))
abort ();
}
void
push_topmost_sequence ()
{
struct sequence_stack *stack, *top = NULL;
start_sequence ();
for (stack = seq_stack; stack; stack = stack->next)
top = stack;
first_insn = top->first;
last_insn = top->last;
seq_rtl_expr = top->sequence_rtl_expr;
}
void
pop_topmost_sequence ()
{
struct sequence_stack *stack, *top = NULL;
for (stack = seq_stack; stack; stack = stack->next)
top = stack;
top->first = first_insn;
top->last = last_insn;
end_sequence ();
}
void
end_sequence ()
{
struct sequence_stack *tem = seq_stack;
first_insn = tem->first;
last_insn = tem->last;
seq_rtl_expr = tem->sequence_rtl_expr;
seq_stack = tem->next;
PFE_FREE (tem);
}
void
end_full_sequence (first, last)
rtx *first, *last;
{
*first = first_insn;
*last = last_insn;
end_sequence();
}
int
in_sequence_p ()
{
return seq_stack != 0;
}
rtx
gen_sequence ()
{
rtx result;
rtx tem;
int i;
int len;
len = 0;
for (tem = first_insn; tem; tem = NEXT_INSN (tem))
len++;
if (len == 1
&& ! RTX_FRAME_RELATED_P (first_insn)
&& GET_CODE (first_insn) == INSN
&& REG_NOTES (first_insn) == 0)
return PATTERN (first_insn);
result = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (len));
for (i = 0, tem = first_insn; tem; tem = NEXT_INSN (tem), i++)
XVECEXP (result, 0, i) = tem;
return result;
}
void
init_virtual_regs (es)
struct emit_status *es;
{
rtx *ptr = es->x_regno_reg_rtx;
ptr[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx;
ptr[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx;
ptr[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;
ptr[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;
ptr[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx;
}
void
clear_emit_caches ()
{
int i;
for (i = 0; i < SEQUENCE_RESULT_SIZE; i++)
sequence_result[i] = 0;
free_insn = 0;
}
static rtx copy_insn_scratch_in[MAX_RECOG_OPERANDS];
static rtx copy_insn_scratch_out[MAX_RECOG_OPERANDS];
static int copy_insn_n_scratches;
static rtvec orig_asm_operands_vector;
static rtvec copy_asm_operands_vector;
static rtvec orig_asm_constraints_vector;
static rtvec copy_asm_constraints_vector;
rtx
copy_insn_1 (orig)
rtx orig;
{
rtx copy;
int i, j;
RTX_CODE code;
const char *format_ptr;
code = GET_CODE (orig);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case CONST_VECTOR:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
case ADDRESSOF:
return orig;
case SCRATCH:
for (i = 0; i < copy_insn_n_scratches; i++)
if (copy_insn_scratch_in[i] == orig)
return copy_insn_scratch_out[i];
break;
case CONST:
if (GET_CODE (XEXP (orig, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
return orig;
break;
default:
break;
}
copy = rtx_alloc (code);
memcpy (copy, orig, sizeof (struct rtx_def) - sizeof (rtunion));
copy->used = 0;
if (GET_RTX_CLASS (code) == 'i')
{
copy->jump = 0;
copy->call = 0;
copy->frame_related = 0;
}
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
copy->fld[i] = orig->fld[i];
switch (*format_ptr++)
{
case 'e':
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = copy_insn_1 (XEXP (orig, i));
break;
case 'E':
case 'V':
if (XVEC (orig, i) == orig_asm_constraints_vector)
XVEC (copy, i) = copy_asm_constraints_vector;
else if (XVEC (orig, i) == orig_asm_operands_vector)
XVEC (copy, i) = copy_asm_operands_vector;
else if (XVEC (orig, i) != NULL)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
XVECEXP (copy, i, j) = copy_insn_1 (XVECEXP (orig, i, j));
}
break;
case 't':
case 'w':
case 'i':
case 's':
case 'S':
case 'u':
case '0':
break;
default:
abort ();
}
}
if (code == SCRATCH)
{
i = copy_insn_n_scratches++;
if (i >= MAX_RECOG_OPERANDS)
abort ();
copy_insn_scratch_in[i] = orig;
copy_insn_scratch_out[i] = copy;
}
else if (code == ASM_OPERANDS)
{
orig_asm_operands_vector = ASM_OPERANDS_INPUT_VEC (orig);
copy_asm_operands_vector = ASM_OPERANDS_INPUT_VEC (copy);
orig_asm_constraints_vector = ASM_OPERANDS_INPUT_CONSTRAINT_VEC (orig);
copy_asm_constraints_vector = ASM_OPERANDS_INPUT_CONSTRAINT_VEC (copy);
}
return copy;
}
rtx
copy_insn (insn)
rtx insn;
{
copy_insn_n_scratches = 0;
orig_asm_operands_vector = 0;
orig_asm_constraints_vector = 0;
copy_asm_operands_vector = 0;
copy_asm_constraints_vector = 0;
return copy_insn_1 (insn);
}
void
init_emit ()
{
struct function *f = cfun;
f->emit = (struct emit_status *)
PFE_MALLOC (sizeof (struct emit_status), PFE_ALLOC_EMIT_STATUS);
first_insn = NULL;
last_insn = NULL;
seq_rtl_expr = NULL;
cur_insn_uid = 1;
reg_rtx_no = LAST_VIRTUAL_REGISTER + 1;
last_linenum = 0;
last_filename = 0;
first_label_num = label_num;
last_label_num = 0;
seq_stack = NULL;
clear_emit_caches ();
f->emit->regno_pointer_align_length = LAST_VIRTUAL_REGISTER + 101;
f->emit->regno_pointer_align
= (unsigned char *) PFE_CALLOC (f->emit->regno_pointer_align_length,
sizeof (unsigned char),
PFE_ALLOC_REGNO_POINTER_ALIGN);
regno_reg_rtx
= (rtx *) PFE_CALLOC (f->emit->regno_pointer_align_length,
sizeof (rtx), PFE_ALLOC_REGNO_REG_RTX);
f->emit->regno_decl
= (tree *) PFE_CALLOC (f->emit->regno_pointer_align_length,
sizeof (tree), PFE_ALLOC_REGNO_DECL);
init_virtual_regs (f->emit);
REG_POINTER (stack_pointer_rtx) = 1;
REG_POINTER (frame_pointer_rtx) = 1;
REG_POINTER (hard_frame_pointer_rtx) = 1;
REG_POINTER (arg_pointer_rtx) = 1;
REG_POINTER (virtual_incoming_args_rtx) = 1;
REG_POINTER (virtual_stack_vars_rtx) = 1;
REG_POINTER (virtual_stack_dynamic_rtx) = 1;
REG_POINTER (virtual_outgoing_args_rtx) = 1;
REG_POINTER (virtual_cfa_rtx) = 1;
#ifdef STACK_BOUNDARY
REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY;
REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = STACK_BOUNDARY;
REGNO_POINTER_ALIGN (VIRTUAL_INCOMING_ARGS_REGNUM) = STACK_BOUNDARY;
REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM) = STACK_BOUNDARY;
REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM) = STACK_BOUNDARY;
REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM) = STACK_BOUNDARY;
REGNO_POINTER_ALIGN (VIRTUAL_CFA_REGNUM) = BITS_PER_WORD;
#endif
#ifdef INIT_EXPANDERS
INIT_EXPANDERS;
#endif
}
static void
mark_sequence_stack (ss)
struct sequence_stack *ss;
{
while (ss)
{
ggc_mark_rtx (ss->first);
ggc_mark_tree (ss->sequence_rtl_expr);
ss = ss->next;
}
}
void
mark_emit_status (es)
struct emit_status *es;
{
rtx *r;
tree *t;
int i;
if (es == 0)
return;
for (i = es->regno_pointer_align_length, r = es->x_regno_reg_rtx,
t = es->regno_decl;
i > 0; --i, ++r, ++t)
{
ggc_mark_rtx (*r);
ggc_mark_tree (*t);
}
mark_sequence_stack (es->sequence_stack);
ggc_mark_tree (es->sequence_rtl_expr);
ggc_mark_rtx (es->x_first_insn);
}
#ifdef PFE
#define PFE_BEGIN_DOING_THE_FOLLOWING_IF_NOT_LOAD(x) \
if (pfe_operation != PFE_LOAD) {
#define PFE_END_DOING_THE_ABOVE_IF_NOT_LOAD(x) \
}
#else
#define PFE_BEGIN_DOING_THE_FOLLOWING_IF_NOT_LOAD(x)
#define PFE_END_DOING_THE_ABOVE_IF_NOT_LOAD(x)
#endif
static rtx
gen_const_vector_0 (mode)
enum machine_mode mode;
{
rtx tem;
rtvec v;
int units, i;
enum machine_mode inner;
units = GET_MODE_NUNITS (mode);
inner = GET_MODE_INNER (mode);
v = rtvec_alloc (units);
if (!CONST0_RTX (inner))
abort ();
for (i = 0; i < units; ++i)
RTVEC_ELT (v, i) = CONST0_RTX (inner);
tem = gen_rtx_CONST_VECTOR (mode, v);
return tem;
}
void
init_emit_once (line_numbers)
int line_numbers;
{
int i;
enum machine_mode mode;
enum machine_mode double_mode;
const_int_htab = htab_create (37, const_int_htab_hash,
const_int_htab_eq, NULL);
ggc_add_deletable_htab (const_int_htab, 0, 0);
mem_attrs_htab = htab_create (37, mem_attrs_htab_hash,
mem_attrs_htab_eq, NULL);
ggc_add_deletable_htab (mem_attrs_htab, 0, mem_attrs_mark);
no_line_numbers = ! line_numbers;
byte_mode = VOIDmode;
word_mode = VOIDmode;
double_mode = VOIDmode;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
if (GET_MODE_BITSIZE (mode) == BITS_PER_UNIT
&& byte_mode == VOIDmode)
byte_mode = mode;
if (GET_MODE_BITSIZE (mode) == BITS_PER_WORD
&& word_mode == VOIDmode)
word_mode = mode;
}
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
if (GET_MODE_BITSIZE (mode) == DOUBLE_TYPE_SIZE
&& double_mode == VOIDmode)
double_mode = mode;
}
ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0);
PFE_BEGIN_DOING_THE_FOLLOWING_IF_NOT_LOAD(++++++++++++++++++++++++++)
pc_rtx = gen_rtx (PC, VOIDmode);
cc0_rtx = gen_rtx (CC0, VOIDmode);
stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM);
frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);
if (hard_frame_pointer_rtx == 0)
hard_frame_pointer_rtx = gen_raw_REG (Pmode,
HARD_FRAME_POINTER_REGNUM);
if (arg_pointer_rtx == 0)
arg_pointer_rtx = gen_raw_REG (Pmode, ARG_POINTER_REGNUM);
virtual_incoming_args_rtx =
gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);
virtual_stack_vars_rtx =
gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);
virtual_stack_dynamic_rtx =
gen_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM);
virtual_outgoing_args_rtx =
gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM);
virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
PFE_END_DOING_THE_ABOVE_IF_NOT_LOAD(--------------------------------)
ggc_add_rtx_root (global_rtl, GR_MAX);
PFE_BEGIN_DOING_THE_FOLLOWING_IF_NOT_LOAD(++++++++++++++++++++++++++)
#ifdef INIT_EXPANDERS
INIT_EXPANDERS;
#endif
for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
const_int_rtx[i + MAX_SAVED_CONST_INT] =
gen_rtx_raw_CONST_INT (VOIDmode, i);
PFE_END_DOING_THE_ABOVE_IF_NOT_LOAD(--------------------------------)
ggc_add_rtx_root (const_int_rtx, 2 * MAX_SAVED_CONST_INT + 1);
PFE_BEGIN_DOING_THE_FOLLOWING_IF_NOT_LOAD(++++++++++++++++++++++++++)
if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT
&& STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT)
const_true_rtx = const_int_rtx[STORE_FLAG_VALUE + MAX_SAVED_CONST_INT];
else
const_true_rtx = gen_rtx_CONST_INT (VOIDmode, STORE_FLAG_VALUE);
PFE_END_DOING_THE_ABOVE_IF_NOT_LOAD(--------------------------------)
dconst0 = REAL_VALUE_ATOF ("0", double_mode);
dconst1 = REAL_VALUE_ATOF ("1", double_mode);
dconst2 = REAL_VALUE_ATOF ("2", double_mode);
dconstm1 = REAL_VALUE_ATOF ("-1", double_mode);
PFE_BEGIN_DOING_THE_FOLLOWING_IF_NOT_LOAD(++++++++++++++++++++++++++)
for (i = 0; i <= 2; i++)
{
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
rtx tem = rtx_alloc (CONST_DOUBLE);
union real_extract u;
memset ((char *) &u, 0, sizeof u);
u.d = i == 0 ? dconst0 : i == 1 ? dconst1 : dconst2;
if (sizeof (u) < sizeof (HOST_WIDE_INT))
CONST_DOUBLE_LOW (tem) = 0;
if (sizeof (u) < 2 * sizeof (HOST_WIDE_INT))
CONST_DOUBLE_HIGH (tem) = 0;
memcpy (&CONST_DOUBLE_LOW (tem), &u, sizeof u);
CONST_DOUBLE_CHAIN (tem) = NULL_RTX;
PUT_MODE (tem, mode);
const_tiny_rtx[i][(int) mode] = tem;
}
const_tiny_rtx[i][(int) VOIDmode] = GEN_INT (i);
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
const_tiny_rtx[i][(int) mode] = GEN_INT (i);
for (mode = GET_CLASS_NARROWEST_MODE (MODE_PARTIAL_INT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
const_tiny_rtx[i][(int) mode] = GEN_INT (i);
}
for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode);
for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode);
for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i)
if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC)
const_tiny_rtx[0][i] = const0_rtx;
const_tiny_rtx[0][(int) BImode] = const0_rtx;
if (STORE_FLAG_VALUE == 1)
const_tiny_rtx[1][(int) BImode] = const1_rtx;
PFE_END_DOING_THE_ABOVE_IF_NOT_LOAD(--------------------------------)
ggc_add_rtx_root ((rtx *) const_tiny_rtx, sizeof const_tiny_rtx / sizeof (rtx));
ggc_add_rtx_root (&const_true_rtx, 1);
PFE_BEGIN_DOING_THE_FOLLOWING_IF_NOT_LOAD(++++++++++++++++++++++++++)
#ifdef RETURN_ADDRESS_POINTER_REGNUM
return_address_pointer_rtx
= gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
#endif
#ifdef STRUCT_VALUE
struct_value_rtx = STRUCT_VALUE;
#else
struct_value_rtx = gen_rtx_REG (Pmode, STRUCT_VALUE_REGNUM);
#endif
#ifdef STRUCT_VALUE_INCOMING
struct_value_incoming_rtx = STRUCT_VALUE_INCOMING;
#else
#ifdef STRUCT_VALUE_INCOMING_REGNUM
struct_value_incoming_rtx
= gen_rtx_REG (Pmode, STRUCT_VALUE_INCOMING_REGNUM);
#else
struct_value_incoming_rtx = struct_value_rtx;
#endif
#endif
#ifdef STATIC_CHAIN_REGNUM
static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
#ifdef STATIC_CHAIN_INCOMING_REGNUM
if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM)
static_chain_incoming_rtx
= gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
else
#endif
static_chain_incoming_rtx = static_chain_rtx;
#endif
#ifdef STATIC_CHAIN
static_chain_rtx = STATIC_CHAIN;
#ifdef STATIC_CHAIN_INCOMING
static_chain_incoming_rtx = STATIC_CHAIN_INCOMING;
#else
static_chain_incoming_rtx = static_chain_rtx;
#endif
#endif
if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
PFE_END_DOING_THE_ABOVE_IF_NOT_LOAD(--------------------------------)
ggc_add_rtx_root (&pic_offset_table_rtx, 1);
ggc_add_rtx_root (&struct_value_rtx, 1);
ggc_add_rtx_root (&struct_value_incoming_rtx, 1);
ggc_add_rtx_root (&static_chain_rtx, 1);
ggc_add_rtx_root (&static_chain_incoming_rtx, 1);
ggc_add_rtx_root (&return_address_pointer_rtx, 1);
}
int
force_line_numbers ()
{
int old = no_line_numbers;
no_line_numbers = 0;
if (old)
force_next_line_note ();
return old;
}
void
restore_line_number_status (old_value)
int old_value;
{
no_line_numbers = old_value;
}
#ifdef PFE
void
pfe_freeze_thaw_emitrtl (hdr)
pfe_compiler_state *hdr;
{
PFE_GLOBAL_TO_HDR_IF_FREEZING (label_num);
PFE_HDR_TO_GLOBAL_IF_THAWING (label_num);
}
#endif