#include "config.h"
#include "system.h"
#include "rtl.h"
#include "real.h"
#include "bitmap.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
extern struct obstack *rtl_obstack;
int rtx_length[NUM_RTX_CODE + 1];
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) NAME ,
char *rtx_name[] = {
#include "rtl.def"
};
#undef DEF_RTL_EXPR
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) NAME,
char *mode_name[(int) MAX_MACHINE_MODE + 1] = {
#include "machmode.def"
#ifdef EXTRA_CC_MODES
EXTRA_CC_NAMES,
#endif
""
};
#undef DEF_MACHMODE
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) CLASS,
enum mode_class mode_class[(int) MAX_MACHINE_MODE] = {
#include "machmode.def"
};
#undef DEF_MACHMODE
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) SIZE,
int mode_size[(int) MAX_MACHINE_MODE] = {
#include "machmode.def"
};
#undef DEF_MACHMODE
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) UNIT,
int mode_unit_size[(int) MAX_MACHINE_MODE] = {
#include "machmode.def"
};
#undef DEF_MACHMODE
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) \
(unsigned char) WIDER,
unsigned char mode_wider_mode[(int) MAX_MACHINE_MODE] = {
#include "machmode.def"
};
#undef DEF_MACHMODE
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) \
((SIZE) * BITS_PER_UNIT >= HOST_BITS_PER_WIDE_INT) ? ~(unsigned HOST_WIDE_INT)0 : ((unsigned HOST_WIDE_INT) 1 << (SIZE) * BITS_PER_UNIT) - 1,
unsigned HOST_WIDE_INT mode_mask_array[(int) MAX_MACHINE_MODE] = {
#include "machmode.def"
};
enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS];
char *rtx_format[] = {
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) FORMAT ,
#include "rtl.def"
#undef DEF_RTL_EXPR
};
char rtx_class[] = {
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) CLASS,
#include "rtl.def"
#undef DEF_RTL_EXPR
};
#ifndef EXTRA_NOTE_NAMES
#define EXTRA_NOTE_NAMES
#endif
char *note_insn_name[] = { 0 , "NOTE_INSN_DELETED",
"NOTE_INSN_BLOCK_BEG", "NOTE_INSN_BLOCK_END",
"NOTE_INSN_LOOP_BEG", "NOTE_INSN_LOOP_END",
"NOTE_INSN_FUNCTION_END", "NOTE_INSN_SETJMP",
"NOTE_INSN_LOOP_CONT", "NOTE_INSN_LOOP_VTOP",
"NOTE_INSN_PROLOGUE_END", "NOTE_INSN_EPILOGUE_BEG",
"NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG",
"NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
"NOTE_REPEATED_LINE_NUMBER", "NOTE_INSN_RANGE_START",
"NOTE_INSN_RANGE_END", "NOTE_INSN_LIVE",
"NOTE_INSN_BASIC_BLOCK" EXTRA_NOTE_NAMES };
char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
"REG_EQUAL", "REG_RETVAL", "REG_LIBCALL",
"REG_NONNEG", "REG_NO_CONFLICT", "REG_UNUSED",
"REG_CC_SETTER", "REG_CC_USER", "REG_LABEL",
"REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
"REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA",
"REG_BR_PRED", "REG_EH_CONTEXT",
"REG_FRAME_RELATED_EXPR", "REG_EH_REGION",
"REG_EH_RETHROW" };
static void dump_and_abort PROTO((int, int, FILE *)) ATTRIBUTE_NORETURN;
static void read_name PROTO((char *, FILE *));
rtvec
rtvec_alloc (n)
int n;
{
rtvec rt;
int i;
rt = (rtvec) obstack_alloc (rtl_obstack,
sizeof (struct rtvec_def)
+ (( n - 1) * sizeof (rtunion)));
PUT_NUM_ELEM (rt, n);
for (i = 0; i < n; i++)
rt->elem[i].rtwint = 0;
return rt;
}
rtx
rtx_alloc (code)
RTX_CODE code;
{
rtx rt;
register struct obstack *ob = rtl_obstack;
register int nelts = GET_RTX_LENGTH (code);
register int length = sizeof (struct rtx_def)
+ (nelts - 1) * sizeof (rtunion);
length = (length + ob->alignment_mask) & ~ ob->alignment_mask;
if (ob->chunk_limit - ob->next_free < length)
_obstack_newchunk (ob, length);
rt = (rtx)ob->object_base;
ob->next_free += length;
ob->object_base = ob->next_free;
memset (rt, 0, sizeof (struct rtx_def) - sizeof (rtunion));
PUT_CODE (rt, code);
return rt;
}
void
rtx_free (x)
rtx x;
{
obstack_free (rtl_obstack, x);
}
rtx
copy_rtx (orig)
register rtx orig;
{
register rtx copy;
register int i, j;
register RTX_CODE code;
register char *format_ptr;
code = GET_CODE (orig);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
case SCRATCH:
case ADDRESSOF:
return orig;
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++)
{
switch (*format_ptr++)
{
case 'e':
XEXP (copy, i) = XEXP (orig, i);
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = copy_rtx (XEXP (orig, i));
break;
case '0':
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_rtx (XVECEXP (orig, i, j));
}
break;
case 'b':
{
bitmap new_bits = BITMAP_OBSTACK_ALLOC (rtl_obstack);
bitmap_copy (new_bits, XBITMAP (orig, i));
XBITMAP (copy, i) = new_bits;
break;
}
case 't':
XTREE (copy, i) = XTREE (orig, i);
break;
case 'w':
XWINT (copy, i) = XWINT (orig, i);
break;
case 'i':
XINT (copy, i) = XINT (orig, i);
break;
case 's':
case 'S':
XSTR (copy, i) = XSTR (orig, i);
break;
default:
abort ();
}
}
return copy;
}
rtx
copy_most_rtx (orig, may_share)
register rtx orig;
register rtx may_share;
{
register rtx copy;
register int i, j;
register RTX_CODE code;
register char *format_ptr;
if (orig == may_share)
return orig;
code = GET_CODE (orig);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
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;
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 '0':
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 's':
case 'S':
XSTR (copy, i) = XSTR (orig, i);
break;
default:
abort ();
}
}
return copy;
}
rtx
shallow_copy_rtx (orig)
rtx orig;
{
register int i;
register char *format_ptr;
register RTX_CODE code = GET_CODE (orig);
register rtx 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;
for (i = 0; i < GET_RTX_LENGTH (code); i++)
copy->fld[i] = orig->fld[i];
return copy;
}
static void
dump_and_abort (expected_c, actual_c, infile)
int expected_c, actual_c;
FILE *infile;
{
int c, i;
if (expected_c >= 0)
fprintf (stderr,
"Expected character %c. Found character %c.",
expected_c, actual_c);
fprintf (stderr, " At file position: %ld\n", ftell (infile));
fprintf (stderr, "Following characters are:\n\t");
for (i = 0; i < 200; i++)
{
c = getc (infile);
if (EOF == c) break;
putc (c, stderr);
}
fprintf (stderr, "Aborting.\n");
abort ();
}
int
read_skip_spaces (infile)
FILE *infile;
{
register int c;
while ((c = getc (infile)))
{
if (c == ' ' || c == '\n' || c == '\t' || c == '\f')
;
else if (c == ';')
{
while ((c = getc (infile)) && c != '\n' && c != EOF)
;
}
else if (c == '/')
{
register int prevc;
c = getc (infile);
if (c != '*')
dump_and_abort ('*', c, infile);
prevc = 0;
while ((c = getc (infile)) && c != EOF)
{
if (prevc == '*' && c == '/')
break;
prevc = c;
}
}
else break;
}
return c;
}
static void
read_name (str, infile)
char *str;
FILE *infile;
{
register char *p;
register int c;
c = read_skip_spaces(infile);
p = str;
while (1)
{
if (c == ' ' || c == '\n' || c == '\t' || c == '\f')
break;
if (c == ':' || c == ')' || c == ']' || c == '"' || c == '/'
|| c == '(' || c == '[')
{
ungetc (c, infile);
break;
}
*p++ = c;
c = getc (infile);
}
if (p == str)
{
fprintf (stderr, "missing name or number");
dump_and_abort (-1, -1, infile);
}
*p = 0;
}
#if HOST_BITS_PER_WIDE_INT > HOST_BITS_PER_LONG && !defined(HAVE_ATOLL) && !defined(HAVE_ATOQ)
HOST_WIDE_INT
atoll(p)
const char *p;
{
int neg = 0;
HOST_WIDE_INT tmp_wide;
while (ISSPACE(*p))
p++;
if (*p == '-')
neg = 1, p++;
else if (*p == '+')
p++;
tmp_wide = 0;
while (ISDIGIT(*p))
{
HOST_WIDE_INT new_wide = tmp_wide*10 + (*p - '0');
if (new_wide < tmp_wide)
{
tmp_wide = (~(unsigned HOST_WIDE_INT)0) >> 1;
break;
}
tmp_wide = new_wide;
p++;
}
if (neg)
tmp_wide = -tmp_wide;
return tmp_wide;
}
#endif
rtx
read_rtx (infile)
FILE *infile;
{
register int i, j, list_counter;
RTX_CODE tmp_code;
register char *format_ptr;
char tmp_char[256];
rtx return_rtx;
register int c;
int tmp_int;
HOST_WIDE_INT tmp_wide;
struct rtx_list
{
struct rtx_list *next;
rtx value;
};
c = read_skip_spaces (infile);
if (c != '(')
dump_and_abort ('(', c, infile);
read_name (tmp_char, infile);
tmp_code = UNKNOWN;
for (i=0; i < NUM_RTX_CODE; i++)
{
if (!(strcmp (tmp_char, GET_RTX_NAME (i))))
{
tmp_code = (RTX_CODE) i;
break;
}
}
if (tmp_code == UNKNOWN)
{
fprintf (stderr,
"Unknown rtx read in rtl.read_rtx(). Code name was %s .",
tmp_char);
}
if (tmp_code == NIL)
{
while ((c = getc (infile)) && c != ')');
return 0;
}
return_rtx = rtx_alloc (tmp_code);
format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx));
i = read_skip_spaces (infile);
if (i == ':')
{
register int k;
read_name (tmp_char, infile);
for (k = 0; k < NUM_MACHINE_MODES; k++)
if (!strcmp (GET_MODE_NAME (k), tmp_char))
break;
PUT_MODE (return_rtx, (enum machine_mode) k );
}
else
ungetc (i, infile);
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (return_rtx)); i++)
switch (*format_ptr++)
{
case '0':
break;
case 'e':
case 'u':
XEXP (return_rtx, i) = read_rtx (infile);
break;
case 'V':
c = read_skip_spaces (infile);
ungetc (c, infile);
if (c == ')')
{
XVEC (return_rtx, i) = 0;
break;
}
case 'E':
{
register struct rtx_list *next_rtx, *rtx_list_link;
struct rtx_list *list_rtx = NULL;
c = read_skip_spaces (infile);
if (c != '[')
dump_and_abort ('[', c, infile);
next_rtx = NULL;
list_counter = 0;
while ((c = read_skip_spaces (infile)) && c != ']')
{
ungetc (c, infile);
list_counter++;
rtx_list_link = (struct rtx_list *)
alloca (sizeof (struct rtx_list));
rtx_list_link->value = read_rtx (infile);
if (next_rtx == 0)
list_rtx = rtx_list_link;
else
next_rtx->next = rtx_list_link;
next_rtx = rtx_list_link;
rtx_list_link->next = 0;
}
XVEC (return_rtx, i) = (list_counter
? rtvec_alloc (list_counter) : NULL_RTVEC);
if (list_counter > 0)
{
next_rtx = list_rtx;
for (j = 0; j < list_counter; j++,
next_rtx = next_rtx->next)
XVECEXP (return_rtx, i, j) = next_rtx->value;
}
}
break;
case 'S':
c = read_skip_spaces (infile);
ungetc (c, infile);
if (c == ')')
{
XSTR (return_rtx, i) = 0;
break;
}
case 's':
{
int saw_paren = 0;
register char *stringbuf;
c = read_skip_spaces (infile);
if (c == '(')
{
saw_paren = 1;
c = read_skip_spaces (infile);
}
if (c != '"')
dump_and_abort ('"', c, infile);
while (1)
{
c = getc (infile);
if (c == '\\')
{
c = getc (infile);
if (c == ';')
{
obstack_grow (rtl_obstack, "\\n\\t", 4);
continue;
}
}
else if (c == '"')
break;
obstack_1grow (rtl_obstack, c);
}
obstack_1grow (rtl_obstack, 0);
stringbuf = (char *) obstack_finish (rtl_obstack);
if (saw_paren)
{
c = read_skip_spaces (infile);
if (c != ')')
dump_and_abort (')', c, infile);
}
XSTR (return_rtx, i) = stringbuf;
}
break;
case 'w':
read_name (tmp_char, infile);
#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
tmp_wide = atoi (tmp_char);
#else
#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
tmp_wide = atol (tmp_char);
#else
#if defined(HAVE_ATOLL) || !defined(HAVE_ATOQ)
tmp_wide = atoll (tmp_char);
#else
tmp_wide = atoq (tmp_char);
#endif
#endif
#endif
XWINT (return_rtx, i) = tmp_wide;
break;
case 'i':
case 'n':
read_name (tmp_char, infile);
tmp_int = atoi (tmp_char);
XINT (return_rtx, i) = tmp_int;
break;
default:
fprintf (stderr,
"switch format wrong in rtl.read_rtx(). format was: %c.\n",
format_ptr[-1]);
fprintf (stderr, "\tfile position: %ld\n", ftell (infile));
abort ();
}
c = read_skip_spaces (infile);
if (c != ')')
dump_and_abort (')', c, infile);
return return_rtx;
}
void
init_rtl ()
{
int min_class_size[(int) MAX_MODE_CLASS];
enum machine_mode mode;
int i;
for (i = 0; i < NUM_RTX_CODE; i++)
rtx_length[i] = strlen (rtx_format[i]);
#ifdef REAL_VALUE_TYPE
i = sizeof (REAL_VALUE_TYPE) / sizeof (rtunion) + 2;
if (rtx_length[(int) CONST_DOUBLE] < i)
{
char *s = (char *) xmalloc (i + 1);
rtx_length[(int) CONST_DOUBLE] = i;
rtx_format[(int) CONST_DOUBLE] = s;
*s++ = 'e';
*s++ = '0';
for (i = 2; i < rtx_length[(int) CONST_DOUBLE]; i++)
*s++ = 'w';
*s++ = 0;
}
#endif
#ifdef EXTRA_CC_MODES
for (i = (int) CCmode + 1; i < (int) MAX_MACHINE_MODE; i++)
{
mode_class[i] = MODE_CC;
mode_mask_array[i] = mode_mask_array[(int) CCmode];
mode_size[i] = mode_size[(int) CCmode];
mode_unit_size[i] = mode_unit_size[(int) CCmode];
mode_wider_mode[i - 1] = i;
mode_wider_mode[i] = (unsigned char)VOIDmode;
}
#endif
for (i = 0; i < (int) MAX_MODE_CLASS; i++)
min_class_size[i] = 1000;
for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
mode = (enum machine_mode) ((int) mode + 1))
{
if (GET_MODE_SIZE (mode) < min_class_size[(int) GET_MODE_CLASS (mode)])
{
class_narrowest_mode[(int) GET_MODE_CLASS (mode)] = mode;
min_class_size[(int) GET_MODE_CLASS (mode)] = GET_MODE_SIZE (mode);
}
}
}