#include "config.h"
#include "system.h"
#include "rtl.h"
static int rtx_addr_can_trap_p PROTO((rtx));
static void reg_set_p_1 PROTO((rtx, rtx));
static void reg_set_last_1 PROTO((rtx, rtx));
static int jmp_uses_reg_or_mem PROTO((rtx));
int target_flags;
int
rtx_unstable_p (x)
rtx x;
{
register RTX_CODE code = GET_CODE (x);
register int i;
register char *fmt;
if (code == MEM)
return ! RTX_UNCHANGING_P (x);
if (code == QUEUED)
return 1;
if (code == CONST || code == CONST_INT)
return 0;
if (code == REG)
return ! (REGNO (x) == FRAME_POINTER_REGNUM
|| REGNO (x) == HARD_FRAME_POINTER_REGNUM
|| REGNO (x) == ARG_POINTER_REGNUM
|| RTX_UNCHANGING_P (x));
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
if (rtx_unstable_p (XEXP (x, i)))
return 1;
return 0;
}
int
rtx_varies_p (x)
rtx x;
{
register RTX_CODE code = GET_CODE (x);
register int i;
register char *fmt;
switch (code)
{
case MEM:
case QUEUED:
return 1;
case CONST:
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case LABEL_REF:
return 0;
case REG:
return ! (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
|| x == arg_pointer_rtx || x == pic_offset_table_rtx);
case LO_SUM:
return rtx_varies_p (XEXP (x, 1));
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
if (rtx_varies_p (XEXP (x, i)))
return 1;
return 0;
}
static int
rtx_addr_can_trap_p (x)
register rtx x;
{
register enum rtx_code code = GET_CODE (x);
switch (code)
{
case SYMBOL_REF:
case LABEL_REF:
return 0;
case REG:
return ! (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
|| x == stack_pointer_rtx || x == arg_pointer_rtx);
case CONST:
return rtx_addr_can_trap_p (XEXP (x, 0));
case PLUS:
return (rtx_addr_can_trap_p (XEXP (x, 0))
|| GET_CODE (XEXP (x, 1)) != CONST_INT);
case LO_SUM:
return rtx_addr_can_trap_p (XEXP (x, 1));
default:
break;
}
return 1;
}
int
rtx_addr_varies_p (x)
rtx x;
{
register enum rtx_code code;
register int i;
register char *fmt;
if (x == 0)
return 0;
code = GET_CODE (x);
if (code == MEM)
return GET_MODE (x) == BLKmode || rtx_varies_p (XEXP (x, 0));
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
{
if (rtx_addr_varies_p (XEXP (x, i)))
return 1;
}
else if (fmt[i] == 'E')
{
int j;
for (j = 0; j < XVECLEN (x, i); j++)
if (rtx_addr_varies_p (XVECEXP (x, i, j)))
return 1;
}
return 0;
}
HOST_WIDE_INT
get_integer_term (x)
rtx x;
{
if (GET_CODE (x) == CONST)
x = XEXP (x, 0);
if (GET_CODE (x) == MINUS
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
return - INTVAL (XEXP (x, 1));
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
return INTVAL (XEXP (x, 1));
return 0;
}
rtx
get_related_value (x)
rtx x;
{
if (GET_CODE (x) != CONST)
return 0;
x = XEXP (x, 0);
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
return XEXP (x, 0);
else if (GET_CODE (x) == MINUS
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
return XEXP (x, 0);
return 0;
}
int
reg_mentioned_p (reg, in)
register rtx reg, in;
{
register char *fmt;
register int i;
register enum rtx_code code;
if (in == 0)
return 0;
if (reg == in)
return 1;
if (GET_CODE (in) == LABEL_REF)
return reg == XEXP (in, 0);
code = GET_CODE (in);
switch (code)
{
case REG:
return GET_CODE (reg) == REG && REGNO (in) == REGNO (reg);
case SCRATCH:
case CC0:
case PC:
return 0;
case CONST_INT:
return GET_CODE (reg) == CONST_INT && INTVAL (in) == INTVAL (reg);
case CONST_DOUBLE:
return 0;
default:
break;
}
if (GET_CODE (reg) == code && rtx_equal_p (reg, in))
return 1;
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (in, i) - 1; j >= 0; j--)
if (reg_mentioned_p (reg, XVECEXP (in, i, j)))
return 1;
}
else if (fmt[i] == 'e'
&& reg_mentioned_p (reg, XEXP (in, i)))
return 1;
}
return 0;
}
int
no_labels_between_p (beg, end)
rtx beg, end;
{
register rtx p;
for (p = NEXT_INSN (beg); p != end; p = NEXT_INSN (p))
if (GET_CODE (p) == CODE_LABEL)
return 0;
return 1;
}
int
no_jumps_between_p (beg, end)
rtx beg, end;
{
register rtx p;
for (p = NEXT_INSN (beg); p != end; p = NEXT_INSN (p))
if (GET_CODE (p) == JUMP_INSN)
return 0;
return 1;
}
int
reg_used_between_p (reg, from_insn, to_insn)
rtx reg, from_insn, to_insn;
{
register rtx insn;
if (from_insn == to_insn)
return 0;
for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& (reg_overlap_mentioned_p (reg, PATTERN (insn))
|| (GET_CODE (insn) == CALL_INSN
&& (find_reg_fusage (insn, USE, reg)
|| find_reg_fusage (insn, CLOBBER, reg)))))
return 1;
return 0;
}
int
reg_referenced_p (x, body)
rtx x;
rtx body;
{
int i;
switch (GET_CODE (body))
{
case SET:
if (reg_overlap_mentioned_p (x, SET_SRC (body)))
return 1;
if (GET_CODE (SET_DEST (body)) != CC0
&& GET_CODE (SET_DEST (body)) != PC
&& GET_CODE (SET_DEST (body)) != REG
&& ! (GET_CODE (SET_DEST (body)) == SUBREG
&& GET_CODE (SUBREG_REG (SET_DEST (body))) == REG
&& (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (body))))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SET_DEST (body)))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
&& reg_overlap_mentioned_p (x, SET_DEST (body)))
return 1;
return 0;
case ASM_OPERANDS:
for (i = ASM_OPERANDS_INPUT_LENGTH (body) - 1; i >= 0; i--)
if (reg_overlap_mentioned_p (x, ASM_OPERANDS_INPUT (body, i)))
return 1;
return 0;
case CALL:
case USE:
return reg_overlap_mentioned_p (x, body);
case TRAP_IF:
return reg_overlap_mentioned_p (x, TRAP_CONDITION (body));
case UNSPEC:
case UNSPEC_VOLATILE:
case PARALLEL:
for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
if (reg_referenced_p (x, XVECEXP (body, 0, i)))
return 1;
return 0;
default:
return 0;
}
}
int
reg_referenced_between_p (reg, from_insn, to_insn)
rtx reg, from_insn, to_insn;
{
register rtx insn;
if (from_insn == to_insn)
return 0;
for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& (reg_referenced_p (reg, PATTERN (insn))
|| (GET_CODE (insn) == CALL_INSN
&& find_reg_fusage (insn, USE, reg))))
return 1;
return 0;
}
int
reg_set_between_p (reg, from_insn, to_insn)
rtx reg, from_insn, to_insn;
{
register rtx insn;
if (from_insn == to_insn)
return 0;
for (insn = NEXT_INSN (from_insn); insn != to_insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& reg_set_p (reg, insn))
return 1;
return 0;
}
static rtx reg_set_reg;
static int reg_set_flag;
static void
reg_set_p_1 (x, pat)
rtx x;
rtx pat ATTRIBUTE_UNUSED;
{
if ((GET_CODE (x) != MEM)
&& reg_overlap_mentioned_p (reg_set_reg, x))
reg_set_flag = 1;
}
int
reg_set_p (reg, insn)
rtx reg, insn;
{
rtx body = insn;
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
if (FIND_REG_INC_NOTE (insn, reg)
|| (GET_CODE (insn) == CALL_INSN
&& ((GET_CODE (reg) == REG
&& REGNO (reg) < FIRST_PSEUDO_REGISTER)
|| GET_CODE (reg) == MEM
|| find_reg_fusage (insn, CLOBBER, reg))))
return 1;
body = PATTERN (insn);
}
reg_set_reg = reg;
reg_set_flag = 0;
note_stores (body, reg_set_p_1);
return reg_set_flag;
}
int
regs_set_between_p (x, start, end)
rtx x;
rtx start, end;
{
enum rtx_code code = GET_CODE (x);
char *fmt;
int i, j;
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
case CONST:
case SYMBOL_REF:
case LABEL_REF:
case PC:
case CC0:
return 0;
case REG:
return reg_set_between_p (x, start, end);
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e' && regs_set_between_p (XEXP (x, i), start, end))
return 1;
else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if (regs_set_between_p (XVECEXP (x, i, j), start, end))
return 1;
}
return 0;
}
int
modified_between_p (x, start, end)
rtx x;
rtx start, end;
{
enum rtx_code code = GET_CODE (x);
char *fmt;
int i, j;
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
case CONST:
case SYMBOL_REF:
case LABEL_REF:
return 0;
case PC:
case CC0:
return 1;
case MEM:
if (! RTX_UNCHANGING_P (x))
return 1;
break;
case REG:
return reg_set_between_p (x, start, end);
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e' && modified_between_p (XEXP (x, i), start, end))
return 1;
if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if (modified_between_p (XVECEXP (x, i, j), start, end))
return 1;
}
return 0;
}
int
modified_in_p (x, insn)
rtx x;
rtx insn;
{
enum rtx_code code = GET_CODE (x);
char *fmt;
int i, j;
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
case CONST:
case SYMBOL_REF:
case LABEL_REF:
return 0;
case PC:
case CC0:
return 1;
case MEM:
if (! RTX_UNCHANGING_P (x))
return 1;
break;
case REG:
return reg_set_p (x, insn);
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e' && modified_in_p (XEXP (x, i), insn))
return 1;
if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if (modified_in_p (XVECEXP (x, i, j), insn))
return 1;
}
return 0;
}
rtx
single_set (insn)
rtx insn;
{
rtx set;
int i;
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
return 0;
if (GET_CODE (PATTERN (insn)) == SET)
return PATTERN (insn);
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
for (i = 0, set = 0; i < XVECLEN (PATTERN (insn), 0); i++)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET
&& (! find_reg_note (insn, REG_UNUSED,
SET_DEST (XVECEXP (PATTERN (insn), 0, i)))
|| side_effects_p (XVECEXP (PATTERN (insn), 0, i))))
{
if (set)
return 0;
else
set = XVECEXP (PATTERN (insn), 0, i);
}
return set;
}
return 0;
}
int
multiple_sets (insn)
rtx insn;
{
int found;
int i;
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
return 0;
if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
for (i = 0, found = 0; i < XVECLEN (PATTERN (insn), 0); i++)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
{
if (found)
return 1;
else
found = 1;
}
}
return 0;
}
rtx
find_last_value (x, pinsn, valid_to, allow_hwreg)
rtx x;
rtx *pinsn;
rtx valid_to;
int allow_hwreg;
{
rtx p;
for (p = PREV_INSN (*pinsn); p && GET_CODE (p) != CODE_LABEL;
p = PREV_INSN (p))
if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
{
rtx set = single_set (p);
rtx note = find_reg_note (p, REG_EQUAL, NULL_RTX);
if (set && rtx_equal_p (x, SET_DEST (set)))
{
rtx src = SET_SRC (set);
if (note && GET_CODE (XEXP (note, 0)) != EXPR_LIST)
src = XEXP (note, 0);
if (! modified_between_p (src, PREV_INSN (p), valid_to)
&& (! (GET_CODE (src) == REG
&& REGNO (src) < FIRST_PSEUDO_REGISTER) || allow_hwreg))
{
*pinsn = p;
return src;
}
}
if (reg_set_p (x, p))
break;
}
return x;
}
int
refers_to_regno_p (regno, endregno, x, loc)
int regno, endregno;
rtx x;
rtx *loc;
{
register int i;
register RTX_CODE code;
register char *fmt;
repeat:
if (x == 0)
return 0;
code = GET_CODE (x);
switch (code)
{
case REG:
i = REGNO (x);
if ((i == STACK_POINTER_REGNUM
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
|| i == ARG_POINTER_REGNUM
#endif
|| i == FRAME_POINTER_REGNUM)
&& regno >= FIRST_VIRTUAL_REGISTER && regno <= LAST_VIRTUAL_REGISTER)
return 1;
return (endregno > i
&& regno < i + (i < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (i, GET_MODE (x))
: 1));
case SUBREG:
if (GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER)
{
int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
int inner_endregno
= inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
return endregno > inner_regno && regno < inner_endregno;
}
break;
case CLOBBER:
case SET:
if (&SET_DEST (x) != loc
&& ((GET_CODE (SET_DEST (x)) == SUBREG
&& loc != &SUBREG_REG (SET_DEST (x))
&& GET_CODE (SUBREG_REG (SET_DEST (x))) == REG
&& REGNO (SUBREG_REG (SET_DEST (x))) >= FIRST_PSEUDO_REGISTER
&& refers_to_regno_p (regno, endregno,
SUBREG_REG (SET_DEST (x)), loc))
|| (GET_CODE (SET_DEST (x)) != REG
&& refers_to_regno_p (regno, endregno, SET_DEST (x), loc))))
return 1;
if (code == CLOBBER || loc == &SET_SRC (x))
return 0;
x = SET_SRC (x);
goto repeat;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e' && loc != &XEXP (x, i))
{
if (i == 0)
{
x = XEXP (x, 0);
goto repeat;
}
else
if (refers_to_regno_p (regno, endregno, XEXP (x, i), loc))
return 1;
}
else if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (x, i) - 1; j >=0; j--)
if (loc != &XVECEXP (x, i, j)
&& refers_to_regno_p (regno, endregno, XVECEXP (x, i, j), loc))
return 1;
}
}
return 0;
}
int
reg_overlap_mentioned_p (x, in)
rtx x, in;
{
int regno, endregno;
if (GET_CODE (x) == STRICT_LOW_PART)
x = XEXP (x, 0);
if (CONSTANT_P (x) || CONSTANT_P (in))
return 0;
else if (GET_CODE (x) == SUBREG)
{
regno = REGNO (SUBREG_REG (x));
if (regno < FIRST_PSEUDO_REGISTER)
regno += SUBREG_WORD (x);
}
else if (GET_CODE (x) == REG)
regno = REGNO (x);
else if (GET_CODE (x) == MEM)
{
char *fmt;
int i;
if (GET_CODE (in) == MEM)
return 1;
fmt = GET_RTX_FORMAT (GET_CODE (in));
for (i = GET_RTX_LENGTH (GET_CODE (in)) - 1; i >= 0; i--)
if (fmt[i] == 'e' && reg_overlap_mentioned_p (x, XEXP (in, i)))
return 1;
return 0;
}
else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC
|| GET_CODE (x) == CC0)
return reg_mentioned_p (x, in);
else if (GET_CODE (x) == PARALLEL
&& GET_MODE (x) == BLKmode)
{
register int i;
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
if (reg_overlap_mentioned_p (SET_DEST (XVECEXP (x, 0, i)), in))
return 1;
return 0;
}
else
abort ();
endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1);
return refers_to_regno_p (regno, endregno, in, NULL_PTR);
}
static int reg_set_last_unknown;
static rtx reg_set_last_value;
static int reg_set_last_first_regno, reg_set_last_last_regno;
static void
reg_set_last_1 (x, pat)
rtx x;
rtx pat;
{
int first, last;
if (GET_CODE (x) != REG)
return;
first = REGNO (x);
last = first + (first < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (first, GET_MODE (x)) : 1);
if (first >= reg_set_last_last_regno
|| last <= reg_set_last_first_regno)
return;
if (GET_CODE (pat) == CLOBBER || SET_DEST (pat) != x
|| first != reg_set_last_first_regno
|| last != reg_set_last_last_regno)
reg_set_last_unknown = 1;
else
reg_set_last_value = SET_SRC (pat);
}
rtx
reg_set_last (x, insn)
rtx x;
rtx insn;
{
rtx orig_insn = insn;
reg_set_last_first_regno = REGNO (x);
reg_set_last_last_regno
= reg_set_last_first_regno
+ (reg_set_last_first_regno < FIRST_PSEUDO_REGISTER
? HARD_REGNO_NREGS (reg_set_last_first_regno, GET_MODE (x)) : 1);
reg_set_last_unknown = 0;
reg_set_last_value = 0;
for (;
insn && GET_CODE (insn) != CODE_LABEL
&& ! (GET_CODE (insn) == CALL_INSN
&& reg_set_last_last_regno <= FIRST_PSEUDO_REGISTER);
insn = PREV_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
note_stores (PATTERN (insn), reg_set_last_1);
if (reg_set_last_unknown)
return 0;
else if (reg_set_last_value)
{
if (CONSTANT_P (reg_set_last_value)
|| ((GET_CODE (reg_set_last_value) == REG
|| GET_CODE (reg_set_last_value) == SUBREG)
&& ! reg_set_between_p (reg_set_last_value,
insn, orig_insn)))
return reg_set_last_value;
else
return 0;
}
}
return 0;
}
int rtx_equal_function_value_matters;
int
rtx_equal_p (x, y)
rtx x, y;
{
register int i;
register int j;
register enum rtx_code code;
register char *fmt;
if (x == y)
return 1;
if (x == 0 || y == 0)
return 0;
code = GET_CODE (x);
if (code != GET_CODE (y))
return 0;
if (GET_MODE (x) != GET_MODE (y))
return 0;
if (code == REG)
return (REGNO (x) == REGNO (y)
&& (! rtx_equal_function_value_matters
|| REG_FUNCTION_VALUE_P (x) == REG_FUNCTION_VALUE_P (y)));
else if (code == LABEL_REF)
return XEXP (x, 0) == XEXP (y, 0);
else if (code == SYMBOL_REF)
return XSTR (x, 0) == XSTR (y, 0);
else if (code == SCRATCH || code == CONST_DOUBLE)
return 0;
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
switch (fmt[i])
{
case 'w':
if (XWINT (x, i) != XWINT (y, i))
return 0;
break;
case 'n':
case 'i':
if (XINT (x, i) != XINT (y, i))
return 0;
break;
case 'V':
case 'E':
if (XVECLEN (x, i) != XVECLEN (y, i))
return 0;
for (j = 0; j < XVECLEN (x, i); j++)
if (rtx_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0)
return 0;
break;
case 'e':
if (rtx_equal_p (XEXP (x, i), XEXP (y, i)) == 0)
return 0;
break;
case 'S':
case 's':
if (strcmp (XSTR (x, i), XSTR (y, i)))
return 0;
break;
case 'u':
break;
case '0':
break;
default:
abort ();
}
}
return 1;
}
void
note_stores (x, fun)
register rtx x;
void (*fun) PROTO ((rtx, rtx));
{
if ((GET_CODE (x) == SET || GET_CODE (x) == CLOBBER))
{
register rtx dest = SET_DEST (x);
while ((GET_CODE (dest) == SUBREG
&& (GET_CODE (SUBREG_REG (dest)) != REG
|| REGNO (SUBREG_REG (dest)) >= FIRST_PSEUDO_REGISTER))
|| GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == SIGN_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == PARALLEL
&& GET_MODE (dest) == BLKmode)
{
register int i;
for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
(*fun) (SET_DEST (XVECEXP (dest, 0, i)), x);
}
else
(*fun) (dest, x);
}
else if (GET_CODE (x) == PARALLEL)
{
register int i;
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
{
register rtx y = XVECEXP (x, 0, i);
if (GET_CODE (y) == SET || GET_CODE (y) == CLOBBER)
{
register rtx dest = SET_DEST (y);
while ((GET_CODE (dest) == SUBREG
&& (GET_CODE (SUBREG_REG (dest)) != REG
|| (REGNO (SUBREG_REG (dest))
>= FIRST_PSEUDO_REGISTER)))
|| GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == SIGN_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == PARALLEL
&& GET_MODE (dest) == BLKmode)
{
register int i;
for (i = XVECLEN (dest, 0) - 1; i >= 0; i--)
(*fun) (SET_DEST (XVECEXP (dest, 0, i)), y);
}
else
(*fun) (dest, y);
}
}
}
}
int
dead_or_set_p (insn, x)
rtx insn;
rtx x;
{
register int regno, last_regno;
register int i;
if (GET_CODE (x) == CC0)
return 1;
if (GET_CODE (x) != REG)
abort ();
regno = REGNO (x);
last_regno = (regno >= FIRST_PSEUDO_REGISTER ? regno
: regno + HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1);
for (i = regno; i <= last_regno; i++)
if (! dead_or_set_regno_p (insn, i))
return 0;
return 1;
}
int
dead_or_set_regno_p (insn, test_regno)
rtx insn;
int test_regno;
{
int regno, endregno;
rtx link;
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
{
if (REG_NOTE_KIND (link) != REG_DEAD
|| GET_CODE (XEXP (link, 0)) != REG)
continue;
regno = REGNO (XEXP (link, 0));
endregno = (regno >= FIRST_PSEUDO_REGISTER ? regno + 1
: regno + HARD_REGNO_NREGS (regno,
GET_MODE (XEXP (link, 0))));
if (test_regno >= regno && test_regno < endregno)
return 1;
}
if (GET_CODE (insn) == CALL_INSN
&& find_regno_fusage (insn, CLOBBER, test_regno))
return 1;
if (GET_CODE (PATTERN (insn)) == SET)
{
rtx dest = SET_DEST (PATTERN (insn));
if (GET_CODE (dest) == SUBREG
&& (((GET_MODE_SIZE (GET_MODE (dest))
+ UNITS_PER_WORD - 1) / UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
+ UNITS_PER_WORD - 1) / UNITS_PER_WORD)))
dest = SUBREG_REG (dest);
if (GET_CODE (dest) != REG)
return 0;
regno = REGNO (dest);
endregno = (regno >= FIRST_PSEUDO_REGISTER ? regno + 1
: regno + HARD_REGNO_NREGS (regno, GET_MODE (dest)));
return (test_regno >= regno && test_regno < endregno);
}
else if (GET_CODE (PATTERN (insn)) == PARALLEL)
{
register int i;
for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
{
rtx body = XVECEXP (PATTERN (insn), 0, i);
if (GET_CODE (body) == SET || GET_CODE (body) == CLOBBER)
{
rtx dest = SET_DEST (body);
if (GET_CODE (dest) == SUBREG
&& (((GET_MODE_SIZE (GET_MODE (dest))
+ UNITS_PER_WORD - 1) / UNITS_PER_WORD)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
+ UNITS_PER_WORD - 1) / UNITS_PER_WORD)))
dest = SUBREG_REG (dest);
if (GET_CODE (dest) != REG)
continue;
regno = REGNO (dest);
endregno = (regno >= FIRST_PSEUDO_REGISTER ? regno + 1
: regno + HARD_REGNO_NREGS (regno, GET_MODE (dest)));
if (test_regno >= regno && test_regno < endregno)
return 1;
}
}
}
return 0;
}
rtx
find_reg_note (insn, kind, datum)
rtx insn;
enum reg_note kind;
rtx datum;
{
register rtx link;
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
return 0;
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == kind
&& (datum == 0 || datum == XEXP (link, 0)))
return link;
return 0;
}
rtx
find_regno_note (insn, kind, regno)
rtx insn;
enum reg_note kind;
int regno;
{
register rtx link;
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
return 0;
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == kind
&& GET_CODE (XEXP (link, 0)) == REG
&& REGNO (XEXP (link, 0)) <= regno
&& ((REGNO (XEXP (link, 0))
+ (REGNO (XEXP (link, 0)) >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (REGNO (XEXP (link, 0)),
GET_MODE (XEXP (link, 0)))))
> regno))
return link;
return 0;
}
int
find_reg_fusage (insn, code, datum)
rtx insn;
enum rtx_code code;
rtx datum;
{
if (GET_CODE (insn) != CALL_INSN)
return 0;
if (! datum)
abort();
if (GET_CODE (datum) != REG)
{
register rtx link;
for (link = CALL_INSN_FUNCTION_USAGE (insn);
link;
link = XEXP (link, 1))
if (GET_CODE (XEXP (link, 0)) == code
&& rtx_equal_p (datum, SET_DEST (XEXP (link, 0))))
return 1;
}
else
{
register int regno = REGNO (datum);
if (regno < FIRST_PSEUDO_REGISTER)
{
int end_regno = regno + HARD_REGNO_NREGS (regno, GET_MODE (datum));
int i;
for (i = regno; i < end_regno; i++)
if (find_regno_fusage (insn, code, i))
return 1;
}
}
return 0;
}
int
find_regno_fusage (insn, code, regno)
rtx insn;
enum rtx_code code;
int regno;
{
register rtx link;
if (regno >= FIRST_PSEUDO_REGISTER
|| GET_CODE (insn) != CALL_INSN )
return 0;
for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
{
register int regnote;
register rtx op;
if (GET_CODE (op = XEXP (link, 0)) == code
&& GET_CODE (SET_DEST (op)) == REG
&& (regnote = REGNO (SET_DEST (op))) <= regno
&& regnote
+ HARD_REGNO_NREGS (regnote, GET_MODE (SET_DEST (op)))
> regno)
return 1;
}
return 0;
}
void
remove_note (insn, note)
register rtx note;
register rtx insn;
{
register rtx link;
if (REG_NOTES (insn) == note)
{
REG_NOTES (insn) = XEXP (note, 1);
return;
}
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (XEXP (link, 1) == note)
{
XEXP (link, 1) = XEXP (note, 1);
return;
}
abort ();
}
void
remove_node_from_expr_list (node, listp)
rtx node;
rtx *listp;
{
rtx temp = *listp;
rtx prev = NULL_RTX;
while (temp)
{
if (node == XEXP (temp, 0))
{
if (prev)
XEXP (prev, 1) = XEXP (temp, 1);
else
*listp = XEXP (temp, 1);
return;
}
temp = XEXP (temp, 1);
}
}
int
volatile_insn_p (x)
rtx x;
{
register RTX_CODE code;
code = GET_CODE (x);
switch (code)
{
case LABEL_REF:
case SYMBOL_REF:
case CONST_INT:
case CONST:
case CONST_DOUBLE:
case CC0:
case PC:
case REG:
case SCRATCH:
case CLOBBER:
case ASM_INPUT:
case ADDR_VEC:
case ADDR_DIFF_VEC:
case CALL:
case MEM:
return 0;
case UNSPEC_VOLATILE:
return 1;
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
return 1;
default:
break;
}
{
register char *fmt = GET_RTX_FORMAT (code);
register int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
if (volatile_insn_p (XEXP (x, i)))
return 1;
}
if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
if (volatile_insn_p (XVECEXP (x, i, j)))
return 1;
}
}
}
return 0;
}
int
volatile_refs_p (x)
rtx x;
{
register RTX_CODE code;
code = GET_CODE (x);
switch (code)
{
case LABEL_REF:
case SYMBOL_REF:
case CONST_INT:
case CONST:
case CONST_DOUBLE:
case CC0:
case PC:
case REG:
case SCRATCH:
case CLOBBER:
case ASM_INPUT:
case ADDR_VEC:
case ADDR_DIFF_VEC:
return 0;
case CALL:
case UNSPEC_VOLATILE:
return 1;
case MEM:
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
return 1;
default:
break;
}
{
register char *fmt = GET_RTX_FORMAT (code);
register int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
if (volatile_refs_p (XEXP (x, i)))
return 1;
}
if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
if (volatile_refs_p (XVECEXP (x, i, j)))
return 1;
}
}
}
return 0;
}
int
side_effects_p (x)
rtx x;
{
register RTX_CODE code;
code = GET_CODE (x);
switch (code)
{
case LABEL_REF:
case SYMBOL_REF:
case CONST_INT:
case CONST:
case CONST_DOUBLE:
case CC0:
case PC:
case REG:
case SCRATCH:
case ASM_INPUT:
case ADDR_VEC:
case ADDR_DIFF_VEC:
return 0;
case CLOBBER:
return (GET_MODE (x) != VOIDmode);
case PRE_INC:
case PRE_DEC:
case POST_INC:
case POST_DEC:
case CALL:
case UNSPEC_VOLATILE:
return 1;
case MEM:
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
return 1;
default:
break;
}
{
register char *fmt = GET_RTX_FORMAT (code);
register int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
if (side_effects_p (XEXP (x, i)))
return 1;
}
if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
if (side_effects_p (XVECEXP (x, i, j)))
return 1;
}
}
}
return 0;
}
int
may_trap_p (x)
rtx x;
{
int i;
enum rtx_code code;
char *fmt;
if (x == 0)
return 0;
code = GET_CODE (x);
switch (code)
{
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case LABEL_REF:
case CONST:
case PC:
case CC0:
case REG:
case SCRATCH:
return 0;
case UNSPEC_VOLATILE:
case TRAP_IF:
return 1;
case MEM:
return rtx_addr_can_trap_p (XEXP (x, 0));
case DIV:
case MOD:
case UDIV:
case UMOD:
if (! CONSTANT_P (XEXP (x, 1))
|| GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
return 1;
if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 0)
return 1;
break;
case EXPR_LIST:
return 1;
default:
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
return 1;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
if (may_trap_p (XEXP (x, i)))
return 1;
}
else if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
if (may_trap_p (XVECEXP (x, i, j)))
return 1;
}
}
return 0;
}
int
inequality_comparisons_p (x)
rtx x;
{
register char *fmt;
register int len, i;
register enum rtx_code code = GET_CODE (x);
switch (code)
{
case REG:
case SCRATCH:
case PC:
case CC0:
case CONST_INT:
case CONST_DOUBLE:
case CONST:
case LABEL_REF:
case SYMBOL_REF:
return 0;
case LT:
case LTU:
case GT:
case GTU:
case LE:
case LEU:
case GE:
case GEU:
return 1;
default:
break;
}
len = GET_RTX_LENGTH (code);
fmt = GET_RTX_FORMAT (code);
for (i = 0; i < len; i++)
{
if (fmt[i] == 'e')
{
if (inequality_comparisons_p (XEXP (x, i)))
return 1;
}
else if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if (inequality_comparisons_p (XVECEXP (x, i, j)))
return 1;
}
}
return 0;
}
rtx
replace_rtx (x, from, to)
rtx x, from, to;
{
register int i, j;
register char *fmt;
if (x != 0 && GET_CODE (x) == CONST_DOUBLE)
return x;
if (x == from)
return to;
if (x == 0)
return 0;
fmt = GET_RTX_FORMAT (GET_CODE (x));
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
XEXP (x, i) = replace_rtx (XEXP (x, i), from, to);
else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
XVECEXP (x, i, j) = replace_rtx (XVECEXP (x, i, j), from, to);
}
return x;
}
rtx
replace_regs (x, reg_map, nregs, replace_dest)
rtx x;
rtx *reg_map;
int nregs;
int replace_dest;
{
register enum rtx_code code;
register int i;
register char *fmt;
if (x == 0)
return x;
code = GET_CODE (x);
switch (code)
{
case SCRATCH:
case PC:
case CC0:
case CONST_INT:
case CONST_DOUBLE:
case CONST:
case SYMBOL_REF:
case LABEL_REF:
return x;
case REG:
if (REGNO (x) < nregs && reg_map[REGNO (x)] != 0)
{
if (GET_CODE (reg_map[REGNO (x)]) == SUBREG)
return copy_rtx (reg_map[REGNO (x)]);
return reg_map[REGNO (x)];
}
return x;
case SUBREG:
if (GET_CODE (SUBREG_REG (x)) == REG && REGNO (SUBREG_REG (x)) < nregs
&& reg_map[REGNO (SUBREG_REG (x))] != 0
&& GET_CODE (reg_map[REGNO (SUBREG_REG (x))]) == SUBREG)
{
rtx map_val = reg_map[REGNO (SUBREG_REG (x))];
rtx map_inner = SUBREG_REG (map_val);
if (GET_MODE (x) == GET_MODE (map_inner))
return map_inner;
else
{
SUBREG_REG (x) = map_inner;
SUBREG_WORD (x) += SUBREG_WORD (map_val);
return x;
#if 0
rtx new = rtx_alloc (SUBREG);
PUT_MODE (new, GET_MODE (x));
SUBREG_REG (new) = map_inner;
SUBREG_WORD (new) = SUBREG_WORD (x) + SUBREG_WORD (map_val);
#endif
}
}
break;
case SET:
if (replace_dest)
SET_DEST (x) = replace_regs (SET_DEST (x), reg_map, nregs, 0);
else if (GET_CODE (SET_DEST (x)) == MEM
|| GET_CODE (SET_DEST (x)) == STRICT_LOW_PART)
XEXP (SET_DEST (x), 0) = replace_regs (XEXP (SET_DEST (x), 0),
reg_map, nregs, 0);
else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
break;
SET_SRC (x) = replace_regs (SET_SRC (x), reg_map, nregs, 0);
return x;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
XEXP (x, i) = replace_regs (XEXP (x, i), reg_map, nregs, replace_dest);
if (fmt[i] == 'E')
{
register int j;
for (j = 0; j < XVECLEN (x, i); j++)
XVECEXP (x, i, j) = replace_regs (XVECEXP (x, i, j), reg_map,
nregs, replace_dest);
}
}
return x;
}
static int
jmp_uses_reg_or_mem (x)
rtx x;
{
enum rtx_code code = GET_CODE (x);
int i, j;
char *fmt;
switch (code)
{
case CONST:
case LABEL_REF:
case PC:
return 0;
case REG:
return 1;
case MEM:
return ! (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)));
case IF_THEN_ELSE:
return (jmp_uses_reg_or_mem (XEXP (x, 1))
|| jmp_uses_reg_or_mem (XEXP (x, 2)));
case PLUS: case MINUS: case MULT:
return (jmp_uses_reg_or_mem (XEXP (x, 0))
|| jmp_uses_reg_or_mem (XEXP (x, 1)));
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e'
&& jmp_uses_reg_or_mem (XEXP (x, i)))
return 1;
if (fmt[i] == 'E')
for (j = 0; j < XVECLEN (x, i); j++)
if (jmp_uses_reg_or_mem (XVECEXP (x, i, j)))
return 1;
}
return 0;
}
int
computed_jump_p (insn)
rtx insn;
{
int i;
if (GET_CODE (insn) == JUMP_INSN)
{
rtx pat = PATTERN (insn);
if (GET_CODE (pat) == PARALLEL)
{
int len = XVECLEN (pat, 0);
int has_use_labelref = 0;
for (i = len - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (pat, 0, i)) == USE
&& (GET_CODE (XEXP (XVECEXP (pat, 0, i), 0))
== LABEL_REF))
has_use_labelref = 1;
if (! has_use_labelref)
for (i = len - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (pat, 0, i)) == SET
&& SET_DEST (XVECEXP (pat, 0, i)) == pc_rtx
&& jmp_uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i))))
return 1;
}
else if (GET_CODE (pat) == SET
&& SET_DEST (pat) == pc_rtx
&& jmp_uses_reg_or_mem (SET_SRC (pat)))
return 1;
}
return 0;
}
int
for_each_rtx (x, f, data)
rtx *x;
rtx_function f;
void *data;
{
int result;
int length;
char* format;
int i;
result = (*f)(x, data);
if (result == -1)
return 0;
else if (result != 0)
return result;
if (*x == NULL_RTX)
return 0;
length = GET_RTX_LENGTH (GET_CODE (*x));
format = GET_RTX_FORMAT (GET_CODE (*x));
for (i = 0; i < length; ++i)
{
switch (format[i])
{
case 'e':
result = for_each_rtx (&XEXP (*x, i), f, data);
if (result != 0)
return result;
break;
case 'V':
case 'E':
if (XVEC (*x, i) != 0)
{
int j;
for (j = 0; j < XVECLEN (*x, i); ++j)
{
result = for_each_rtx (&XVECEXP (*x, i, j), f, data);
if (result != 0)
return result;
}
}
break;
default:
break;
}
}
return 0;
}
rtx
regno_use_in (regno, x)
int regno;
rtx x;
{
register char *fmt;
int i, j;
rtx tem;
if (GET_CODE (x) == REG && REGNO (x) == regno)
return x;
fmt = GET_RTX_FORMAT (GET_CODE (x));
for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
{
if ((tem = regno_use_in (regno, XEXP (x, i))))
return tem;
}
else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
if ((tem = regno_use_in (regno , XVECEXP (x, i, j))))
return tem;
}
return NULL_RTX;
}
int
auto_inc_p (x)
rtx x;
{
switch (GET_CODE (x))
{
case PRE_INC:
case POST_INC:
case PRE_DEC:
case POST_DEC:
case PRE_MODIFY:
case POST_MODIFY:
if (XEXP (x, 0) != stack_pointer_rtx)
return 1;
default:
break;
}
return 0;
}