1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-13 10:02:38 +00:00

Here comes the right import of gcc-2.6.0.

This commit is contained in:
Poul-Henning Kamp 1994-08-02 20:15:59 +00:00
parent 5bb6db475f
commit b75deec600
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=1823
173 changed files with 307626 additions and 0 deletions

46
gnu/lib/libgcc/Makefile Normal file
View File

@ -0,0 +1,46 @@
#
# $FreeBSD$
#
LIB= gcc
INSTALL_PIC_ARCHIVE= yes
SHLIB_MAJOR= 26
SHLIB_MINOR= 0
LIB1OBJS= _mulsi3.o _udivsi3.o _divsi3.o _umodsi3.o _modsi3.o _lshrsi3.o _lshlsi3.o _ashrsi3.o _ashlsi3.o _divdf3.o _muldf3.o _negdf2.o _adddf3.o _subdf3.o _fixdfsi.o _fixsfsi.o _floatsidf.o _floatsisf.o _truncdfsf2.o _extendsfdf2.o _addsf3.o _negsf2.o _subsf3.o _mulsf3.o _divsf3.o _eqdf2.o _nedf2.o _gtdf2.o _gedf2.o _ltdf2.o _ledf2.o _eqsf2.o _nesf2.o _gtsf2.o _gesf2.o _ltsf2.o _lesf2.o
LIB2OBJS= _muldi3.o _divdi3.o _moddi3.o _udivdi3.o _umoddi3.o _negdi2.o _lshrdi3.o _lshldi3.o _ashldi3.o _ashrdi3.o _ffsdi2.o _udiv_w_sdiv.o _udivmoddi4.o _cmpdi2.o _ucmpdi2.o _floatdidf.o _floatdisf.o _fixunsdfsi.o _fixunssfsi.o _fixunsdfdi.o _fixdfdi.o _fixunssfdi.o _fixsfdi.o _fixxfdi.o _fixunsxfdi.o _floatdixf.o _fixunsxfsi.o _fixtfdi.o _fixunstfdi.o _floatditf.o __gcc_bcmp.o _varargs.o _eprintf.o _op_new.o _op_vnew.o _new_handler.o _op_delete.o _op_vdel.o _bb.o _shtab.o _clear_cache.o _trampoline.o __main.o _exit.o _ctors.o
OBJS= ${LIB1OBJS} ${LIB2OBJS}
LIB1SOBJS=${LIB1OBJS:.o=.so}
LIB2SOBJS=${LIB2OBJS:.o=.so}
P1OBJS=${LIB1OBJS:.o=.po}
P2OBJS=${LIB2OBJS:.o=.po}
${LIB1OBJS}: libgcc1.c
${CC} -c ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc1.c
@${LD} -x -r ${.TARGET}
@mv a.out ${.TARGET}
${LIB2OBJS}: libgcc2.c
${CC} -c ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc2.c
@${LD} -x -r ${.TARGET}
@mv a.out ${.TARGET}
.if !defined(NOPIC)
${LIB1SOBJS}: libgcc1.c
${CC} -c -fpic ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc1.c
${LIB2SOBJS}: libgcc2.c
${CC} -c -fpic ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc2.c
.endif
.if !defined(NOPROFILE)
${P1OBJS}: libgcc1.c
${CC} -c -p ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc1.c
${P2OBJS}: libgcc2.c
${CC} -c -p ${CFLAGS} -DL${.PREFIX} -o ${.TARGET} ${.CURDIR}/libgcc2.c
.endif
.include <bsd.lib.mk>

8
gnu/usr.bin/cc/Makefile Normal file
View File

@ -0,0 +1,8 @@
#
# $FreeBSD$
#
PGMDIR= cc_int cpp cc1 cc cc1plus c++ libgcc
SUBDIR= $(PGMDIR)
.include <bsd.subdir.mk>

View File

@ -0,0 +1,10 @@
#
# $FreeBSD$
#
CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../include
CFLAGS+= -DGCC_INCLUDE_DIR=\"FOO\"
CFLAGS+= -DDEFAULT_TARGET_VERSION=\"2.6.0\"
CFLAGS+= -DDEFAULT_TARGET_MACHINE=\"i386-unknown-freebsd\"
CFLAGS+= -DMD_EXEC_PREFIX=\"/usr/libexec/\"
CFLAGS+= -DSTANDARD_STARTFILE_PREFIX=\"/usr/lib\"

View File

@ -0,0 +1,13 @@
#
# $FreeBSD$
#
PROG = c++
SRCS = g++.c
BINDIR= /usr/bin
NOMAN= 1
LDDESTDIR+= -L${.CURDIR}/../cc_int/obj
LDDESTDIR+= -L${.CURDIR}/../cc_int
LDADD+= -lcc_int
.include <bsd.prog.mk>

535
gnu/usr.bin/cc/c++/g++.c Normal file
View File

@ -0,0 +1,535 @@
/* G++ preliminary semantic processing for the compiler driver.
Copyright (C) 1993, 1994 Free Software Foundation, Inc.
Contributed by Brendan Kehoe (brendan@cygnus.com).
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This program is a wrapper to the main `gcc' driver. For GNU C++,
we need to do two special things: a) append `-lg++' in situations
where it's appropriate, to link in libg++, and b) add `-xc++'..`-xnone'
around file arguments named `foo.c' or `foo.i'. So, we do all of
this semantic processing then just exec gcc with the new argument
list.
We used to do all of this in a small shell script, but many users
found the performance of this as a shell script to be unacceptable.
In situations where your PATH has a lot of NFS-mounted directories,
using a script that runs sed and other things would be a nasty
performance hit. With this program, we never search the PATH at all. */
#include "config.h"
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h> /* May get R_OK, etc. on some systems. */
/* Defined to the name of the compiler; if using a cross compiler, the
Makefile should compile this file with the proper name
(e.g., "i386-aout-gcc"). */
#ifndef GCC_NAME
#define GCC_NAME "gcc"
#endif
/* This bit is set if we saw a `-xfoo' language specification. */
#define LANGSPEC (1<<1)
/* This bit is set if they did `-lm' or `-lmath'. */
#define MATHLIB (1<<2)
/* On MSDOS, write temp files in current dir
because there's no place else we can expect to use. */
#ifdef __MSDOS__
#ifndef P_tmpdir
#define P_tmpdir "."
#endif
#ifndef R_OK
#define R_OK 4
#define W_OK 2
#define X_OK 1
#endif
#endif
#ifndef VPROTO
#ifdef __STDC__
#define PVPROTO(ARGS) ARGS
#define VPROTO(ARGS) ARGS
#define VA_START(va_list,var) va_start(va_list,var)
#else
#define PVPROTO(ARGS) ()
#define VPROTO(ARGS) (va_alist) va_dcl
#define VA_START(va_list,var) va_start(va_list)
#endif
#endif
extern int errno, sys_nerr;
#if defined(bsd4_4) || defined(__NetBSD__)
extern const char *const sys_errlist[];
#else
extern char *sys_errlist[];
#endif
/* Name with which this program was invoked. */
static char *programname;
#ifdef HAVE_VPRINTF
/* Output an error message and exit */
static void
fatal VPROTO((char *format, ...))
{
#ifndef __STDC__
char *format;
#endif
va_list ap;
VA_START (ap, format);
#ifndef __STDC__
format = va_arg (ap, char*);
#endif
fprintf (stderr, "%s: ", programname);
vfprintf (stderr, format, ap);
va_end (ap);
fprintf (stderr, "\n");
#if 0
/* XXX Not needed for g++ driver. */
delete_temp_files ();
#endif
exit (1);
}
static void
error VPROTO((char *format, ...))
{
#ifndef __STDC__
char *format;
#endif
va_list ap;
VA_START (ap, format);
#ifndef __STDC__
format = va_arg (ap, char*);
#endif
fprintf (stderr, "%s: ", programname);
vfprintf (stderr, format, ap);
va_end (ap);
fprintf (stderr, "\n");
}
#else /* not HAVE_VPRINTF */
static void
error (msg, arg1, arg2)
char *msg, *arg1, *arg2;
{
fprintf (stderr, "%s: ", programname);
fprintf (stderr, msg, arg1, arg2);
fprintf (stderr, "\n");
}
static void
fatal (msg, arg1, arg2)
char *msg, *arg1, *arg2;
{
error (msg, arg1, arg2);
#if 0
/* XXX Not needed for g++ driver. */
delete_temp_files ();
#endif
exit (1);
}
#endif /* not HAVE_VPRINTF */
/* More 'friendly' abort that prints the line and file.
config.h can #define abort fancy_abort if you like that sort of thing. */
void
fancy_abort ()
{
fatal ("Internal g++ abort.");
}
char *
xmalloc (size)
unsigned size;
{
register char *value = (char *) malloc (size);
if (value == 0)
fatal ("virtual memory exhausted");
return value;
}
/* Return a newly-allocated string whose contents concatenate those
of s1, s2, s3. */
static char *
concat (s1, s2, s3)
char *s1, *s2, *s3;
{
int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
char *result = xmalloc (len1 + len2 + len3 + 1);
strcpy (result, s1);
strcpy (result + len1, s2);
strcpy (result + len1 + len2, s3);
*(result + len1 + len2 + len3) = 0;
return result;
}
static void
pfatal_with_name (name)
char *name;
{
char *s;
if (errno < sys_nerr)
s = concat ("%s: ", sys_errlist[errno], "");
else
s = "cannot open %s";
fatal (s, name);
}
#ifdef __MSDOS__
/* This is the common prefix we use to make temp file names. */
char *temp_filename;
/* Length of the prefix. */
int temp_filename_length;
/* Compute a string to use as the base of all temporary file names. */
static char *
choose_temp_base_try (try, base)
char *try;
char *base;
{
char *rv;
if (base)
rv = base;
else if (try == (char *)0)
rv = 0;
else if (access (try, R_OK | W_OK) != 0)
rv = 0;
else
rv = try;
return rv;
}
static void
choose_temp_base ()
{
char *base = 0;
int len;
base = choose_temp_base_try (getenv ("TMPDIR"), base);
base = choose_temp_base_try (getenv ("TMP"), base);
base = choose_temp_base_try (getenv ("TEMP"), base);
#ifdef P_tmpdir
base = choose_temp_base_try (P_tmpdir, base);
#endif
base = choose_temp_base_try ("/usr/tmp", base);
base = choose_temp_base_try ("/tmp", base);
/* If all else fails, use the current directory! */
if (base == (char *)0)
base = "./";
len = strlen (base);
temp_filename = xmalloc (len + sizeof("/ccXXXXXX"));
strcpy (temp_filename, base);
if (len > 0 && temp_filename[len-1] != '/')
temp_filename[len++] = '/';
strcpy (temp_filename + len, "ccXXXXXX");
mktemp (temp_filename);
temp_filename_length = strlen (temp_filename);
if (temp_filename_length == 0)
abort ();
}
static void
perror_exec (name)
char *name;
{
char *s;
if (errno < sys_nerr)
s = concat ("installation problem, cannot exec %s: ",
sys_errlist[errno], "");
else
s = "installation problem, cannot exec %s";
error (s, name);
}
/* This is almost exactly what's in gcc.c:pexecute for MSDOS. */
void
run_dos (program, argv)
char *program;
char *argv[];
{
char *scmd, *rf;
FILE *argfile;
int i;
choose_temp_base (); /* not in gcc.c */
scmd = (char *) malloc (strlen (program) + strlen (temp_filename) + 10);
rf = scmd + strlen (program) + 6;
sprintf (scmd, "%s.exe @%s.gp", program, temp_filename);
argfile = fopen (rf, "w");
if (argfile == 0)
pfatal_with_name (rf);
for (i=1; argv[i]; i++)
{
char *cp;
for (cp = argv[i]; *cp; cp++)
{
if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
fputc ('\\', argfile);
fputc (*cp, argfile);
}
fputc ('\n', argfile);
}
fclose (argfile);
i = system (scmd);
remove (rf);
if (i == -1)
perror_exec (program);
}
#endif /* __MSDOS__ */
int
main (argc, argv)
int argc;
char **argv;
{
register int i, j = 0;
register char *p;
int verbose = 0;
/* This will be NULL if we encounter a situation where we should not
link in libg++. */
char *library = "-lg++";
/* Used to track options that take arguments, so we don't go wrapping
those with -xc++/-xnone. */
char *quote = NULL;
/* The new argument list will be contained in this. */
char **arglist;
/* The name of the compiler we will want to run---by default, it
will be the definition of `GCC_NAME', e.g., `gcc'. */
char *gcc = GCC_NAME;
/* Non-zero if we saw a `-xfoo' language specification on the
command line. Used to avoid adding our own -xc++ if the user
already gave a language for the file. */
int saw_speclang = 0;
/* Non-zero if we saw `-lm' or `-lmath' on the command line. */
int saw_math = 0;
/* The number of arguments being added to what's in argv. By
default it's one new argument (adding `-lg++'). We use this
to track the number of times we've inserted -xc++/-xnone as well. */
int added = 1;
/* An array used to flag each argument that needs a bit set for
LANGSPEC or MATHLIB. */
int *args;
p = argv[0] + strlen (argv[0]);
while (p != argv[0] && p[-1] != '/')
--p;
programname = p;
if (argc == 1)
fatal ("No input files specified.\n");
#ifndef __MSDOS__
/* We do a little magic to find out where the main gcc executable
is. If they ran us as /usr/local/bin/g++, then we will look
for /usr/local/bin/gcc; similarly, if they just ran us as `g++',
we'll just look for `gcc'. */
if (p != argv[0])
{
*--p = '\0';
gcc = (char *) malloc ((strlen (argv[0]) + 1 + strlen (GCC_NAME) + 1)
* sizeof (char));
sprintf (gcc, "%s/%s", argv[0], GCC_NAME);
}
#endif
args = (int *) malloc (argc * sizeof (int));
bzero (args, argc * sizeof (int));
for (i = 1; i < argc; i++)
{
/* If the previous option took an argument, we swallow it here. */
if (quote)
{
quote = NULL;
continue;
}
if (argv[i][0] == '\0' || argv[i][1] == '\0')
continue;
if (argv[i][0] == '-')
{
if (strcmp (argv[i], "-nostdlib") == 0)
{
added--;
library = NULL;
}
else if (strcmp (argv[i], "-lm") == 0
|| strcmp (argv[i], "-lmath") == 0)
args[i] |= MATHLIB;
else if (strcmp (argv[i], "-v") == 0)
{
verbose = 1;
if (argc == 2)
{
/* If they only gave us `-v', don't try to link
in libg++. */
added--;
library = NULL;
}
}
else if (strncmp (argv[i], "-x", 2) == 0)
saw_speclang = 1;
else if (((argv[i][2] == '\0'
&& (char *)strchr ("bBVDUoeTuIYmLiA", argv[i][1]) != NULL)
|| strcmp (argv[i], "-Tdata") == 0))
quote = argv[i];
else if (((argv[i][2] == '\0'
&& (char *) strchr ("cSEM", argv[i][1]) != NULL)
|| strcmp (argv[i], "-MM") == 0))
{
/* Don't specify libraries if we won't link, since that would
cause a warning. */
added--;
library = NULL;
}
else
/* Pass other options through. */
continue;
}
else
{
int len;
if (saw_speclang)
continue;
/* If the filename ends in .c or .i, put options around it.
But not if a specified -x option is currently active. */
len = strlen (argv[i]);
if (len > 2
&& (argv[i][len - 1] == 'c' || argv[i][len - 1] == 'i')
&& argv[i][len - 2] == '.')
{
args[i] |= LANGSPEC;
added += 2;
}
}
}
if (quote)
fatal ("argument to `%s' missing\n", quote);
if (added)
{
arglist = (char **) malloc ((argc + added + 1) * sizeof (char *));
for (i = 1, j = 1; i < argc; i++, j++)
{
arglist[j] = argv[i];
/* Make sure -lg++ is before the math library, since libg++
itself uses those math routines. */
if (!saw_math && (args[i] & MATHLIB) && library)
{
saw_math = 1;
arglist[j] = library;
arglist[++j] = argv[i];
}
/* Wrap foo.c and foo.i files in a language specification to
force the gcc compiler driver to run cc1plus on them. */
if (args[i] & LANGSPEC)
{
int len = strlen (argv[i]);
if (argv[i][len - 1] == 'i')
arglist[j++] = "-xc++-cpp-output";
else
arglist[j++] = "-xc++";
arglist[j++] = argv[i];
arglist[j] = "-xnone";
}
}
/* Add `-lg++' if we haven't already done so. */
if (library && !saw_math)
arglist[j++] = library;
arglist[j] = NULL;
}
else
/* No need to copy 'em all. */
arglist = argv;
arglist[0] = gcc;
if (verbose)
{
if (j == 0)
j = argc;
for (i = 0; i < j; i++)
fprintf (stderr, " %s", arglist[i]);
fprintf (stderr, "\n");
}
#ifndef OS2
#ifdef __MSDOS__
run_dos (gcc, arglist);
#else /* !__MSDOS__ */
if (execvp (gcc, arglist) < 0)
pfatal_with_name (gcc);
#endif /* __MSDOS__ */
#else /* OS2 */
if (spawnvp (gcc, arglist) < 0)
pfatal_with_name (gcc);
#endif
return 0;
}

View File

@ -0,0 +1,18 @@
#
# $FreeBSD$
#
PROG = cc
SRCS = gcc.c
BINDIR= /usr/bin
MLINKS+=cc.1 gcc.1
MLINKS+=cc.1 c++.1
MLINKS+=cc.1 g++.1
LDDESTDIR+= -L${.CURDIR}/../cc_int/obj
LDDESTDIR+= -L${.CURDIR}/../cc_int
LDADD+= -lcc_int
afterinstall:
cd $(DESTDIR)$(BINDIR) ; rm gcc ; ln -s cc gcc
.include <bsd.prog.mk>

4111
gnu/usr.bin/cc/cc/cc.1 Normal file

File diff suppressed because it is too large Load Diff

4896
gnu/usr.bin/cc/cc/gcc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
#
# $FreeBSD$
#
PROG = cc1
SRCS = c-aux-info.c c-convert.c c-decl.c c-iterate.c c-lang.c c-lex.c c-parse.c c-pragma.c c-typeck.c
BINDIR= /usr/libexec
NOMAN= 1
LDDESTDIR+= -L${.CURDIR}/../cc_int/obj
LDDESTDIR+= -L${.CURDIR}/../cc_int
LDADD+= -lcc_int
.include <bsd.prog.mk>

View File

@ -0,0 +1,639 @@
/* Generate information regarding function declarations and definitions based
on information stored in GCC's tree structure. This code implements the
-aux-info option.
Copyright (C) 1989, 1991, 1994 Free Software Foundation, Inc.
Contributed by Ron Guilmette (rfg@netcom.com).
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "config.h"
#include "flags.h"
#include "tree.h"
#include "c-tree.h"
extern char* xmalloc ();
enum formals_style_enum {
ansi,
k_and_r_names,
k_and_r_decls
};
typedef enum formals_style_enum formals_style;
static char* data_type;
static char * concat ();
static char * concat3 ();
static char * gen_formal_list_for_type ();
static int deserves_ellipsis ();
static char * gen_formal_list_for_func_def ();
static char * gen_type ();
static char * gen_decl ();
void gen_aux_info_record ();
/* Take two strings and mash them together into a newly allocated area. */
static char*
concat (s1, s2)
char* s1;
char* s2;
{
int size1, size2;
char* ret_val;
if (!s1)
s1 = "";
if (!s2)
s2 = "";
size1 = strlen (s1);
size2 = strlen (s2);
ret_val = xmalloc (size1 + size2 + 1);
strcpy (ret_val, s1);
strcpy (&ret_val[size1], s2);
return ret_val;
}
/* Take three strings and mash them together into a newly allocated area. */
static char*
concat3 (s1, s2, s3)
char* s1;
char* s2;
char* s3;
{
int size1, size2, size3;
char* ret_val;
if (!s1)
s1 = "";
if (!s2)
s2 = "";
if (!s3)
s3 = "";
size1 = strlen (s1);
size2 = strlen (s2);
size3 = strlen (s3);
ret_val = xmalloc (size1 + size2 + size3 + 1);
strcpy (ret_val, s1);
strcpy (&ret_val[size1], s2);
strcpy (&ret_val[size1+size2], s3);
return ret_val;
}
/* Given a string representing an entire type or an entire declaration
which only lacks the actual "data-type" specifier (at its left end),
affix the data-type specifier to the left end of the given type
specification or object declaration.
Because of C language weirdness, the data-type specifier (which normally
goes in at the very left end) may have to be slipped in just to the
right of any leading "const" or "volatile" qualifiers (there may be more
than one). Actually this may not be strictly necessary because it seems
that GCC (at least) accepts `<data-type> const foo;' and treats it the
same as `const <data-type> foo;' but people are accustomed to seeing
`const char *foo;' and *not* `char const *foo;' so we try to create types
that look as expected. */
static char*
affix_data_type (type_or_decl)
char *type_or_decl;
{
char *p = type_or_decl;
char *qualifiers_then_data_type;
char saved;
/* Skip as many leading const's or volatile's as there are. */
for (;;)
{
if (!strncmp (p, "volatile ", 9))
{
p += 9;
continue;
}
if (!strncmp (p, "const ", 6))
{
p += 6;
continue;
}
break;
}
/* p now points to the place where we can insert the data type. We have to
add a blank after the data-type of course. */
if (p == type_or_decl)
return concat3 (data_type, " ", type_or_decl);
saved = *p;
*p = '\0';
qualifiers_then_data_type = concat (type_or_decl, data_type);
*p = saved;
return concat3 (qualifiers_then_data_type, " ", p);
}
/* Given a tree node which represents some "function type", generate the
source code version of a formal parameter list (of some given style) for
this function type. Return the whole formal parameter list (including
a pair of surrounding parens) as a string. Note that if the style
we are currently aiming for is non-ansi, then we just return a pair
of empty parens here. */
static char*
gen_formal_list_for_type (fntype, style)
tree fntype;
formals_style style;
{
char* formal_list = "";
tree formal_type;
if (style != ansi)
return "()";
formal_type = TYPE_ARG_TYPES (fntype);
while (formal_type && TREE_VALUE (formal_type) != void_type_node)
{
char* this_type;
if (*formal_list)
formal_list = concat (formal_list, ", ");
this_type = gen_type ("", TREE_VALUE (formal_type), ansi);
formal_list =
(strlen (this_type))
? concat (formal_list, affix_data_type (this_type))
: concat (formal_list, data_type);
formal_type = TREE_CHAIN (formal_type);
}
/* If we got to here, then we are trying to generate an ANSI style formal
parameters list.
New style prototyped ANSI formal parameter lists should in theory always
contain some stuff between the opening and closing parens, even if it is
only "void".
The brutal truth though is that there is lots of old K&R code out there
which contains declarations of "pointer-to-function" parameters and
these almost never have fully specified formal parameter lists associated
with them. That is, the pointer-to-function parameters are declared
with just empty parameter lists.
In cases such as these, protoize should really insert *something* into
the vacant parameter lists, but what? It has no basis on which to insert
anything in particular.
Here, we make life easy for protoize by trying to distinguish between
K&R empty parameter lists and new-style prototyped parameter lists
that actually contain "void". In the latter case we (obviously) want
to output the "void" verbatim, and that what we do. In the former case,
we do our best to give protoize something nice to insert.
This "something nice" should be something that is still legal (when
re-compiled) but something that can clearly indicate to the user that
more typing information (for the parameter list) should be added (by
hand) at some convenient moment.
The string chosen here is a comment with question marks in it. */
if (!*formal_list)
{
if (TYPE_ARG_TYPES (fntype))
/* assert (TREE_VALUE (TYPE_ARG_TYPES (fntype)) == void_type_node); */
formal_list = "void";
else
formal_list = "/* ??? */";
}
else
{
/* If there were at least some parameters, and if the formals-types-list
petered out to a NULL (i.e. without being terminated by a
void_type_node) then we need to tack on an ellipsis. */
if (!formal_type)
formal_list = concat (formal_list, ", ...");
}
return concat3 (" (", formal_list, ")");
}
/* For the generation of an ANSI prototype for a function definition, we have
to look at the formal parameter list of the function's own "type" to
determine if the function's formal parameter list should end with an
ellipsis. Given a tree node, the following function will return non-zero
if the "function type" parameter list should end with an ellipsis. */
static int
deserves_ellipsis (fntype)
tree fntype;
{
tree formal_type;
formal_type = TYPE_ARG_TYPES (fntype);
while (formal_type && TREE_VALUE (formal_type) != void_type_node)
formal_type = TREE_CHAIN (formal_type);
/* If there were at least some parameters, and if the formals-types-list
petered out to a NULL (i.e. without being terminated by a void_type_node)
then we need to tack on an ellipsis. */
return (!formal_type && TYPE_ARG_TYPES (fntype));
}
/* Generate a parameter list for a function definition (in some given style).
Note that this routine has to be separate (and different) from the code that
generates the prototype parameter lists for function declarations, because
in the case of a function declaration, all we have to go on is a tree node
representing the function's own "function type". This can tell us the types
of all of the formal parameters for the function, but it cannot tell us the
actual *names* of each of the formal parameters. We need to output those
parameter names for each function definition.
This routine gets a pointer to a tree node which represents the actual
declaration of the given function, and this DECL node has a list of formal
parameter (variable) declarations attached to it. These formal parameter
(variable) declaration nodes give us the actual names of the formal
parameters for the given function definition.
This routine returns a string which is the source form for the entire
function formal parameter list. */
static char*
gen_formal_list_for_func_def (fndecl, style)
tree fndecl;
formals_style style;
{
char* formal_list = "";
tree formal_decl;
formal_decl = DECL_ARGUMENTS (fndecl);
while (formal_decl)
{
char *this_formal;
if (*formal_list && ((style == ansi) || (style == k_and_r_names)))
formal_list = concat (formal_list, ", ");
this_formal = gen_decl (formal_decl, 0, style);
if (style == k_and_r_decls)
formal_list = concat3 (formal_list, this_formal, "; ");
else
formal_list = concat (formal_list, this_formal);
formal_decl = TREE_CHAIN (formal_decl);
}
if (style == ansi)
{
if (!DECL_ARGUMENTS (fndecl))
formal_list = concat (formal_list, "void");
if (deserves_ellipsis (TREE_TYPE (fndecl)))
formal_list = concat (formal_list, ", ...");
}
if ((style == ansi) || (style == k_and_r_names))
formal_list = concat3 (" (", formal_list, ")");
return formal_list;
}
/* Generate a string which is the source code form for a given type (t). This
routine is ugly and complex because the C syntax for declarations is ugly
and complex. This routine is straightforward so long as *no* pointer types,
array types, or function types are involved.
In the simple cases, this routine will return the (string) value which was
passed in as the "ret_val" argument. Usually, this starts out either as an
empty string, or as the name of the declared item (i.e. the formal function
parameter variable).
This routine will also return with the global variable "data_type" set to
some string value which is the "basic" data-type of the given complete type.
This "data_type" string can be concatenated onto the front of the returned
string after this routine returns to its caller.
In complicated cases involving pointer types, array types, or function
types, the C declaration syntax requires an "inside out" approach, i.e. if
you have a type which is a "pointer-to-function" type, you need to handle
the "pointer" part first, but it also has to be "innermost" (relative to
the declaration stuff for the "function" type). Thus, is this case, you
must prepend a "(*" and append a ")" to the name of the item (i.e. formal
variable). Then you must append and prepend the other info for the
"function type" part of the overall type.
To handle the "innermost precedence" rules of complicated C declarators, we
do the following (in this routine). The input parameter called "ret_val"
is treated as a "seed". Each time gen_type is called (perhaps recursively)
some additional strings may be appended or prepended (or both) to the "seed"
string. If yet another (lower) level of the GCC tree exists for the given
type (as in the case of a pointer type, an array type, or a function type)
then the (wrapped) seed is passed to a (recursive) invocation of gen_type()
this recursive invocation may again "wrap" the (new) seed with yet more
declarator stuff, by appending, prepending (or both). By the time the
recursion bottoms out, the "seed value" at that point will have a value
which is (almost) the complete source version of the declarator (except
for the data_type info). Thus, this deepest "seed" value is simply passed
back up through all of the recursive calls until it is given (as the return
value) to the initial caller of the gen_type() routine. All that remains
to do at this point is for the initial caller to prepend the "data_type"
string onto the returned "seed". */
static char*
gen_type (ret_val, t, style)
char* ret_val;
tree t;
formals_style style;
{
tree chain_p;
if (TYPE_NAME (t) && DECL_NAME (TYPE_NAME (t)))
data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t)));
else
{
switch (TREE_CODE (t))
{
case POINTER_TYPE:
if (TYPE_READONLY (t))
ret_val = concat ("const ", ret_val);
if (TYPE_VOLATILE (t))
ret_val = concat ("volatile ", ret_val);
ret_val = concat ("*", ret_val);
if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE || TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
ret_val = concat3 ("(", ret_val, ")");
ret_val = gen_type (ret_val, TREE_TYPE (t), style);
return ret_val;
case ARRAY_TYPE:
if (TYPE_SIZE (t) == 0 || TREE_CODE (TYPE_SIZE (t)) != INTEGER_CST)
ret_val = gen_type (concat (ret_val, "[]"), TREE_TYPE (t), style);
else if (int_size_in_bytes (t) == 0)
ret_val = gen_type (concat (ret_val, "[0]"), TREE_TYPE (t), style);
else
{
int size = (int_size_in_bytes (t) / int_size_in_bytes (TREE_TYPE (t)));
char buff[10];
sprintf (buff, "[%d]", size);
ret_val = gen_type (concat (ret_val, buff),
TREE_TYPE (t), style);
}
break;
case FUNCTION_TYPE:
ret_val = gen_type (concat (ret_val, gen_formal_list_for_type (t, style)), TREE_TYPE (t), style);
break;
case IDENTIFIER_NODE:
data_type = IDENTIFIER_POINTER (t);
break;
/* The following three cases are complicated by the fact that a
user may do something really stupid, like creating a brand new
"anonymous" type specification in a formal argument list (or as
part of a function return type specification). For example:
int f (enum { red, green, blue } color);
In such cases, we have no name that we can put into the prototype
to represent the (anonymous) type. Thus, we have to generate the
whole darn type specification. Yuck! */
case RECORD_TYPE:
if (TYPE_NAME (t))
data_type = IDENTIFIER_POINTER (TYPE_NAME (t));
else
{
data_type = "";
chain_p = TYPE_FIELDS (t);
while (chain_p)
{
data_type = concat (data_type, gen_decl (chain_p, 0, ansi));
chain_p = TREE_CHAIN (chain_p);
data_type = concat (data_type, "; ");
}
data_type = concat3 ("{ ", data_type, "}");
}
data_type = concat ("struct ", data_type);
break;
case UNION_TYPE:
if (TYPE_NAME (t))
data_type = IDENTIFIER_POINTER (TYPE_NAME (t));
else
{
data_type = "";
chain_p = TYPE_FIELDS (t);
while (chain_p)
{
data_type = concat (data_type, gen_decl (chain_p, 0, ansi));
chain_p = TREE_CHAIN (chain_p);
data_type = concat (data_type, "; ");
}
data_type = concat3 ("{ ", data_type, "}");
}
data_type = concat ("union ", data_type);
break;
case ENUMERAL_TYPE:
if (TYPE_NAME (t))
data_type = IDENTIFIER_POINTER (TYPE_NAME (t));
else
{
data_type = "";
chain_p = TYPE_VALUES (t);
while (chain_p)
{
data_type = concat (data_type,
IDENTIFIER_POINTER (TREE_PURPOSE (chain_p)));
chain_p = TREE_CHAIN (chain_p);
if (chain_p)
data_type = concat (data_type, ", ");
}
data_type = concat3 ("{ ", data_type, " }");
}
data_type = concat ("enum ", data_type);
break;
case TYPE_DECL:
data_type = IDENTIFIER_POINTER (DECL_NAME (t));
break;
case INTEGER_TYPE:
data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t)));
/* Normally, `unsigned' is part of the deal. Not so if it comes
with `const' or `volatile'. */
if (TREE_UNSIGNED (t) && (TYPE_READONLY (t) || TYPE_VOLATILE (t)))
data_type = concat ("unsigned ", data_type);
break;
case REAL_TYPE:
data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t)));
break;
case VOID_TYPE:
data_type = "void";
break;
default:
abort ();
}
}
if (TYPE_READONLY (t))
ret_val = concat ("const ", ret_val);
if (TYPE_VOLATILE (t))
ret_val = concat ("volatile ", ret_val);
return ret_val;
}
/* Generate a string (source) representation of an entire entity declaration
(using some particular style for function types).
The given entity may be either a variable or a function.
If the "is_func_definition" parameter is non-zero, assume that the thing
we are generating a declaration for is a FUNCTION_DECL node which is
associated with a function definition. In this case, we can assume that
an attached list of DECL nodes for function formal arguments is present. */
static char*
gen_decl (decl, is_func_definition, style)
tree decl;
int is_func_definition;
formals_style style;
{
char* ret_val;
if (DECL_NAME (decl))
ret_val = IDENTIFIER_POINTER (DECL_NAME (decl));
else
ret_val = "";
/* If we are just generating a list of names of formal parameters, we can
simply return the formal parameter name (with no typing information
attached to it) now. */
if (style == k_and_r_names)
return ret_val;
/* Note that for the declaration of some entity (either a function or a
data object, like for instance a parameter) if the entity itself was
declared as either const or volatile, then const and volatile properties
are associated with just the declaration of the entity, and *not* with
the `type' of the entity. Thus, for such declared entities, we have to
generate the qualifiers here. */
if (TREE_THIS_VOLATILE (decl))
ret_val = concat ("volatile ", ret_val);
if (TREE_READONLY (decl))
ret_val = concat ("const ", ret_val);
data_type = "";
/* For FUNCTION_DECL nodes, there are two possible cases here. First, if
this FUNCTION_DECL node was generated from a function "definition", then
we will have a list of DECL_NODE's, one for each of the function's formal
parameters. In this case, we can print out not only the types of each
formal, but also each formal's name. In the second case, this
FUNCTION_DECL node came from an actual function declaration (and *not*
a definition). In this case, we do nothing here because the formal
argument type-list will be output later, when the "type" of the function
is added to the string we are building. Note that the ANSI-style formal
parameter list is considered to be a (suffix) part of the "type" of the
function. */
if (TREE_CODE (decl) == FUNCTION_DECL && is_func_definition)
{
ret_val = concat (ret_val, gen_formal_list_for_func_def (decl, ansi));
/* Since we have already added in the formals list stuff, here we don't
add the whole "type" of the function we are considering (which
would include its parameter-list info), rather, we only add in
the "type" of the "type" of the function, which is really just
the return-type of the function (and does not include the parameter
list info). */
ret_val = gen_type (ret_val, TREE_TYPE (TREE_TYPE (decl)), style);
}
else
ret_val = gen_type (ret_val, TREE_TYPE (decl), style);
ret_val = affix_data_type (ret_val);
if (DECL_REGISTER (decl))
ret_val = concat ("register ", ret_val);
if (TREE_PUBLIC (decl))
ret_val = concat ("extern ", ret_val);
if (TREE_CODE (decl) == FUNCTION_DECL && !TREE_PUBLIC (decl))
ret_val = concat ("static ", ret_val);
return ret_val;
}
extern FILE* aux_info_file;
/* Generate and write a new line of info to the aux-info (.X) file. This
routine is called once for each function declaration, and once for each
function definition (even the implicit ones). */
void
gen_aux_info_record (fndecl, is_definition, is_implicit, is_prototyped)
tree fndecl;
int is_definition;
int is_implicit;
int is_prototyped;
{
if (flag_gen_aux_info)
{
static int compiled_from_record = 0;
/* Each output .X file must have a header line. Write one now if we
have not yet done so. */
if (! compiled_from_record++)
{
/* The first line tells which directory file names are relative to.
Currently, -aux-info works only for files in the working
directory, so just use a `.' as a placeholder for now. */
fprintf (aux_info_file, "/* compiled from: . */\n");
}
/* Write the actual line of auxiliary info. */
fprintf (aux_info_file, "/* %s:%d:%c%c */ %s;",
DECL_SOURCE_FILE (fndecl),
DECL_SOURCE_LINE (fndecl),
(is_implicit) ? 'I' : (is_prototyped) ? 'N' : 'O',
(is_definition) ? 'F' : 'C',
gen_decl (fndecl, is_definition, ansi));
/* If this is an explicit function declaration, we need to also write
out an old-style (i.e. K&R) function header, just in case the user
wants to run unprotoize. */
if (is_definition)
{
fprintf (aux_info_file, " /*%s %s*/",
gen_formal_list_for_func_def (fndecl, k_and_r_names),
gen_formal_list_for_func_def (fndecl, k_and_r_decls));
}
fprintf (aux_info_file, "\n");
}
}

View File

@ -0,0 +1,95 @@
/* Language-level data type conversion for GNU C.
Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This file contains the functions for converting C expressions
to different data types. The only entry point is `convert'.
Every language front end must have a `convert' function
but what kind of conversions it does will depend on the language. */
#include "config.h"
#include "tree.h"
#include "flags.h"
#include "convert.h"
/* Change of width--truncation and extension of integers or reals--
is represented with NOP_EXPR. Proper functioning of many things
assumes that no other conversions can be NOP_EXPRs.
Conversion between integer and pointer is represented with CONVERT_EXPR.
Converting integer to real uses FLOAT_EXPR
and real to integer uses FIX_TRUNC_EXPR.
Here is a list of all the functions that assume that widening and
narrowing is always done with a NOP_EXPR:
In convert.c, convert_to_integer.
In c-typeck.c, build_binary_op (boolean ops), and truthvalue_conversion.
In expr.c: expand_expr, for operands of a MULT_EXPR.
In fold-const.c: fold.
In tree.c: get_narrower and get_unwidened. */
/* Subroutines of `convert'. */
/* Create an expression whose value is that of EXPR,
converted to type TYPE. The TREE_TYPE of the value
is always TYPE. This function implements all reasonable
conversions; callers should filter out those that are
not permitted by the language being compiled. */
tree
convert (type, expr)
tree type, expr;
{
register tree e = expr;
register enum tree_code code = TREE_CODE (type);
if (type == TREE_TYPE (expr)
|| TREE_CODE (expr) == ERROR_MARK)
return expr;
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
return fold (build1 (NOP_EXPR, type, expr));
if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)
return error_mark_node;
if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE)
{
error ("void value not ignored as it ought to be");
return error_mark_node;
}
if (code == VOID_TYPE)
return build1 (CONVERT_EXPR, type, e);
#if 0
/* This is incorrect. A truncation can't be stripped this way.
Extensions will be stripped by the use of get_unwidened. */
if (TREE_CODE (expr) == NOP_EXPR)
return convert (type, TREE_OPERAND (expr, 0));
#endif
if (code == INTEGER_TYPE || code == ENUMERAL_TYPE)
return fold (convert_to_integer (type, e));
if (code == POINTER_TYPE)
return fold (convert_to_pointer (type, e));
if (code == REAL_TYPE)
return fold (convert_to_real (type, e));
if (code == COMPLEX_TYPE)
return fold (convert_to_complex (type, e));
error ("conversion to non-scalar type requested");
return error_mark_node;
}

6797
gnu/usr.bin/cc/cc1/c-decl.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,595 @@
/* Build expressions with type checking for C compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This file is part of the C front end.
It is responsible for implementing iterators,
both their declarations and the expansion of statements using them. */
#include "config.h"
#include <stdio.h>
#include "tree.h"
#include "c-tree.h"
#include "flags.h"
#include "obstack.h"
#include "rtl.h"
static void expand_stmt_with_iterators_1 ();
static tree collect_iterators ();
static void iterator_loop_prologue ();
static void iterator_loop_epilogue ();
static void add_ixpansion ();
static void delete_ixpansion();
static int top_level_ixpansion_p ();
static void istack_sublevel_to_current ();
/* A special obstack, and a pointer to the start of
all the data in it (so we can free everything easily). */
static struct obstack ixp_obstack;
static char *ixp_firstobj;
/*
KEEPING TRACK OF EXPANSIONS
In order to clean out expansions corresponding to statements inside
"{(...)}" constructs we have to keep track of all expansions. The
cleanup is needed when an automatic, or implicit, expansion on
iterator, say X, happens to a statement which contains a {(...)}
form with a statement already expanded on X. In this case we have
to go back and cleanup the inner expansion. This can be further
complicated by the fact that {(...)} can be nested.
To make this cleanup possible, we keep lists of all expansions, and
to make it work for nested constructs, we keep a stack. The list at
the top of the stack (ITER_STACK.CURRENT_LEVEL) corresponds to the
currently parsed level. All expansions of the levels below the
current one are kept in one list whose head is pointed to by
ITER_STACK.SUBLEVEL_FIRST (SUBLEVEL_LAST is there for making merges
easy). The process works as follows:
-- On "({" a new node is added to the stack by PUSH_ITERATOR_STACK.
The sublevel list is not changed at this point.
-- On "})" the list for the current level is appended to the sublevel
list.
-- On ";" sublevel lists are appended to the current level lists.
The reason is this: if they have not been superseded by the
expansion at the current level, they still might be
superseded later by the expansion on the higher level.
The levels do not have to distinguish levels below, so we
can merge the lists together. */
struct ixpansion
{
tree ixdecl; /* Iterator decl */
rtx ixprologue_start; /* First insn of epilogue. NULL means */
/* explicit (FOR) expansion*/
rtx ixprologue_end;
rtx ixepilogue_start;
rtx ixepilogue_end;
struct ixpansion *next; /* Next in the list */
};
struct iter_stack_node
{
struct ixpansion *first; /* Head of list of ixpansions */
struct ixpansion *last; /* Last node in list of ixpansions */
struct iter_stack_node *next; /* Next level iterator stack node */
};
struct iter_stack_node *iter_stack;
struct iter_stack_node sublevel_ixpansions;
/* During collect_iterators, a list of SAVE_EXPRs already scanned. */
static tree save_exprs;
/* Initialize our obstack once per compilation. */
void
init_iterators ()
{
gcc_obstack_init (&ixp_obstack);
ixp_firstobj = (char *) obstack_alloc (&ixp_obstack, 0);
}
/* Handle the start of an explicit `for' loop for iterator IDECL. */
void
iterator_for_loop_start (idecl)
tree idecl;
{
ITERATOR_BOUND_P (idecl) = 1;
add_ixpansion (idecl, 0, 0, 0, 0);
iterator_loop_prologue (idecl, 0, 0);
}
/* Handle the end of an explicit `for' loop for iterator IDECL. */
void
iterator_for_loop_end (idecl)
tree idecl;
{
iterator_loop_epilogue (idecl, 0, 0);
ITERATOR_BOUND_P (idecl) = 0;
}
/*
ITERATOR RTL EXPANSIONS
Expanding simple statements with iterators is straightforward:
collect the list of all free iterators in the statement, and
generate a loop for each of them.
An iterator is "free" if it has not been "bound" by a FOR
operator. The DECL_RTL of the iterator is the loop counter. */
/* Expand a statement STMT, possibly containing iterator usage, into RTL. */
void
iterator_expand (stmt)
tree stmt;
{
tree iter_list;
save_exprs = NULL_TREE;
iter_list = collect_iterators (stmt, NULL_TREE);
expand_stmt_with_iterators_1 (stmt, iter_list);
istack_sublevel_to_current ();
}
static void
expand_stmt_with_iterators_1 (stmt, iter_list)
tree stmt, iter_list;
{
if (iter_list == 0)
expand_expr_stmt (stmt);
else
{
tree current_iterator = TREE_VALUE (iter_list);
tree iter_list_tail = TREE_CHAIN (iter_list);
rtx p_start, p_end, e_start, e_end;
iterator_loop_prologue (current_iterator, &p_start, &p_end);
expand_stmt_with_iterators_1 (stmt, iter_list_tail);
iterator_loop_epilogue (current_iterator, &e_start, &e_end);
/** Delete all inner expansions based on current_iterator **/
/** before adding the outer one. **/
delete_ixpansion (current_iterator);
add_ixpansion (current_iterator, p_start, p_end, e_start, e_end);
}
}
/* Return a list containing all the free (i.e. not bound by a
containing `for' statement) iterators mentioned in EXP, plus those
in LIST. Do not add duplicate entries to the list. */
static tree
collect_iterators (exp, list)
tree exp, list;
{
if (exp == 0) return list;
switch (TREE_CODE (exp))
{
case VAR_DECL:
if (! ITERATOR_P (exp) || ITERATOR_BOUND_P (exp))
return list;
if (value_member (exp, list))
return list;
return tree_cons (NULL_TREE, exp, list);
case TREE_LIST:
{
tree tail;
for (tail = exp; tail; tail = TREE_CHAIN (tail))
list = collect_iterators (TREE_VALUE (tail), list);
return list;
}
case SAVE_EXPR:
/* In each scan, scan a given save_expr only once. */
if (value_member (exp, save_exprs))
return list;
save_exprs = tree_cons (NULL_TREE, exp, save_exprs);
return collect_iterators (TREE_OPERAND (exp, 0), list);
/* we do not automatically iterate blocks -- one must */
/* use the FOR construct to do that */
case BLOCK:
return list;
default:
switch (TREE_CODE_CLASS (TREE_CODE (exp)))
{
case '1':
return collect_iterators (TREE_OPERAND (exp, 0), list);
case '2':
case '<':
return collect_iterators (TREE_OPERAND (exp, 0),
collect_iterators (TREE_OPERAND (exp, 1),
list));
case 'e':
case 'r':
{
int num_args = tree_code_length[(int) TREE_CODE (exp)];
int i;
/* Some tree codes have RTL, not trees, as operands. */
switch (TREE_CODE (exp))
{
case CALL_EXPR:
num_args = 2;
break;
case METHOD_CALL_EXPR:
num_args = 3;
break;
case WITH_CLEANUP_EXPR:
num_args = 1;
break;
case RTL_EXPR:
return list;
}
for (i = 0; i < num_args; i++)
list = collect_iterators (TREE_OPERAND (exp, i), list);
return list;
}
default:
return list;
}
}
}
/* Emit rtl for the start of a loop for iterator IDECL.
If necessary, create loop counter rtx and store it as DECL_RTL of IDECL.
The prologue normally starts and ends with notes, which are returned
by this function in *START_NOTE and *END_NODE.
If START_NOTE and END_NODE are 0, we don't make those notes. */
static void
iterator_loop_prologue (idecl, start_note, end_note)
tree idecl;
rtx *start_note, *end_note;
{
tree expr;
/* Force the save_expr in DECL_INITIAL to be calculated
if it hasn't been calculated yet. */
expand_expr (DECL_INITIAL (idecl), const0_rtx, VOIDmode, 0);
if (DECL_RTL (idecl) == 0)
expand_decl (idecl);
if (start_note)
*start_note = emit_note (0, NOTE_INSN_DELETED);
/* Initialize counter. */
expr = build (MODIFY_EXPR, TREE_TYPE (idecl), idecl, integer_zero_node);
TREE_SIDE_EFFECTS (expr) = 1;
expand_expr (expr, const0_rtx, VOIDmode, 0);
expand_start_loop_continue_elsewhere (1);
ITERATOR_BOUND_P (idecl) = 1;
if (end_note)
*end_note = emit_note (0, NOTE_INSN_DELETED);
}
/* Similar to the previous function, but for the end of the loop.
DECL_RTL is zeroed unless we are inside "({...})". The reason for that is
described below.
When we create two (or more) loops based on the same IDECL, and
both inside the same "({...})" construct, we must be prepared to
delete both of the loops and create a single one on the level
above, i.e. enclosing the "({...})". The new loop has to use the
same counter rtl because the references to the iterator decl
(IDECL) have already been expanded as references to the counter
rtl.
It is incorrect to use the same counter reg in different functions,
and it is desirable to use different counters in disjoint loops
when we know there's no need to combine them (because then they can
get allocated separately). */
static void
iterator_loop_epilogue (idecl, start_note, end_note)
tree idecl;
rtx *start_note, *end_note;
{
tree test, incr;
if (start_note)
*start_note = emit_note (0, NOTE_INSN_DELETED);
expand_loop_continue_here ();
incr = build_binary_op (PLUS_EXPR, idecl, integer_one_node, 0);
incr = build (MODIFY_EXPR, TREE_TYPE (idecl), idecl, incr);
TREE_SIDE_EFFECTS (incr) = 1;
expand_expr (incr, const0_rtx, VOIDmode, 0);
test = build_binary_op (LT_EXPR, idecl, DECL_INITIAL (idecl), 0);
expand_exit_loop_if_false (0, test);
expand_end_loop ();
ITERATOR_BOUND_P (idecl) = 0;
/* we can reset rtl since there is not chance that this expansion */
/* would be superceded by a higher level one */
if (top_level_ixpansion_p ())
DECL_RTL (idecl) = 0;
if (end_note)
*end_note = emit_note (0, NOTE_INSN_DELETED);
}
/* Return true if we are not currently inside a "({...})" construct. */
static int
top_level_ixpansion_p ()
{
return iter_stack == 0;
}
/* Given two chains of iter_stack_nodes,
append the nodes in X into Y. */
static void
isn_append (x, y)
struct iter_stack_node *x, *y;
{
if (x->first == 0)
return;
if (y->first == 0)
{
y->first = x->first;
y->last = x->last;
}
else
{
y->last->next = x->first;
y->last = x->last;
}
}
/** Make X empty **/
#define ISN_ZERO(X) (X).first=(X).last=0
/* Move the ixpansions in sublevel_ixpansions into the current
node on the iter_stack, or discard them if the iter_stack is empty.
We do this at the end of a statement. */
static void
istack_sublevel_to_current ()
{
/* At the top level we can throw away sublevel's expansions **/
/* because there is nobody above us to ask for a cleanup **/
if (iter_stack != 0)
/** Merging with empty sublevel list is a no-op **/
if (sublevel_ixpansions.last)
isn_append (&sublevel_ixpansions, iter_stack);
if (iter_stack == 0)
obstack_free (&ixp_obstack, ixp_firstobj);
ISN_ZERO (sublevel_ixpansions);
}
/* Push a new node on the iter_stack, when we enter a ({...}). */
void
push_iterator_stack ()
{
struct iter_stack_node *new_top
= (struct iter_stack_node*)
obstack_alloc (&ixp_obstack, sizeof (struct iter_stack_node));
new_top->first = 0;
new_top->last = 0;
new_top->next = iter_stack;
iter_stack = new_top;
}
/* Pop iter_stack, moving the ixpansions in the node being popped
into sublevel_ixpansions. */
void
pop_iterator_stack ()
{
if (iter_stack == 0)
abort ();
isn_append (iter_stack, &sublevel_ixpansions);
/** Pop current level node: */
iter_stack = iter_stack->next;
}
/* Record an iterator expansion ("ixpansion") for IDECL.
The remaining paramters are the notes in the loop entry
and exit rtl. */
static void
add_ixpansion (idecl, pro_start, pro_end, epi_start, epi_end)
tree idecl;
rtx pro_start, pro_end, epi_start, epi_end;
{
struct ixpansion* newix;
/* Do nothing if we are not inside "({...})",
as in that case this expansion can't need subsequent RTL modification. */
if (iter_stack == 0)
return;
newix = (struct ixpansion*) obstack_alloc (&ixp_obstack,
sizeof (struct ixpansion));
newix->ixdecl = idecl;
newix->ixprologue_start = pro_start;
newix->ixprologue_end = pro_end;
newix->ixepilogue_start = epi_start;
newix->ixepilogue_end = epi_end;
newix->next = iter_stack->first;
iter_stack->first = newix;
if (iter_stack->last == 0)
iter_stack->last = newix;
}
/* Delete the RTL for all ixpansions for iterator IDECL
in our sublevels. We do this when we make a larger
containing expansion for IDECL. */
static void
delete_ixpansion (idecl)
tree idecl;
{
struct ixpansion* previx = 0, *ix;
for (ix = sublevel_ixpansions.first; ix; ix = ix->next)
if (ix->ixdecl == idecl)
{
/** zero means that this is a mark for FOR -- **/
/** we do not delete anything, just issue an error. **/
if (ix->ixprologue_start == 0)
error_with_decl (idecl,
"`for (%s)' appears within implicit iteration");
else
{
rtx insn;
/* We delete all insns, including notes because leaving loop */
/* notes and barriers produced by iterator expansion would */
/* be misleading to other phases */
for (insn = NEXT_INSN (ix->ixprologue_start);
insn != ix->ixprologue_end;
insn = NEXT_INSN (insn))
delete_insn (insn);
for (insn = NEXT_INSN (ix->ixepilogue_start);
insn != ix->ixepilogue_end;
insn = NEXT_INSN (insn))
delete_insn (insn);
}
/* Delete this ixpansion from sublevel_ixpansions. */
if (previx)
previx->next = ix->next;
else
sublevel_ixpansions.first = ix->next;
if (sublevel_ixpansions.last == ix)
sublevel_ixpansions.last = previx;
}
else
previx = ix;
}
#ifdef DEBUG_ITERATORS
/* The functions below are for use from source level debugger.
They print short forms of iterator lists and the iterator stack. */
/* Print the name of the iterator D. */
void
prdecl (d)
tree d;
{
if (d)
{
if (TREE_CODE (d) == VAR_DECL)
{
tree tname = DECL_NAME (d);
char *dname = IDENTIFIER_POINTER (tname);
fprintf (stderr, dname);
}
else
fprintf (stderr, "<<Not a Decl!!!>>");
}
else
fprintf (stderr, "<<NULL!!>>");
}
/* Print Iterator List -- names only */
tree
pil (head)
tree head;
{
tree current, next;
for (current = head; current; current = next)
{
tree node = TREE_VALUE (current);
prdecl (node);
next = TREE_CHAIN (current);
if (next) fprintf (stderr, ",");
}
fprintf (stderr, "\n");
}
/* Print IXpansion List */
struct ixpansion *
pixl (head)
struct ixpansion *head;
{
struct ixpansion *current, *next;
fprintf (stderr, "> ");
if (head == 0)
fprintf (stderr, "(empty)");
for (current=head; current; current = next)
{
tree node = current->ixdecl;
prdecl (node);
next = current->next;
if (next)
fprintf (stderr, ",");
}
fprintf (stderr, "\n");
return head;
}
/* Print Iterator Stack*/
void
pis ()
{
struct iter_stack_node *stack_node;
fprintf (stderr, "--SubLevel: ");
pixl (sublevel_ixpansions.first);
fprintf (stderr, "--Stack:--\n");
for (stack_node = iter_stack;
stack_node;
stack_node = stack_node->next)
pixl (stack_node->first);
}
#endif /* DEBUG_ITERATORS */

129
gnu/usr.bin/cc/cc1/c-lang.c Normal file
View File

@ -0,0 +1,129 @@
/* Language-specific hook definitions for C front end.
Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include "tree.h"
#include <stdio.h>
#include "input.h"
/* Each of the functions defined here
is an alternative to a function in objc-actions.c. */
int
lang_decode_option (p)
char *p;
{
return c_decode_option (p);
}
void
lang_init ()
{
/* the beginning of the file is a new line; check for # */
/* With luck, we discover the real source file's name from that
and put it in input_filename. */
ungetc (check_newline (), finput);
}
void
lang_finish ()
{
}
char *
lang_identify ()
{
return "c";
}
void
print_lang_statistics ()
{
}
/* Used by c-lex.c, but only for objc. */
tree
lookup_interface (arg)
tree arg;
{
return 0;
}
tree
is_class_name (arg)
tree arg;
{
return 0;
}
void
maybe_objc_check_decl (decl)
tree decl;
{
}
int
maybe_objc_comptypes (lhs, rhs, reflexive)
tree lhs, rhs;
int reflexive;
{
return -1;
}
tree
maybe_objc_method_name (decl)
tree decl;
{
return 0;
}
tree
maybe_building_objc_message_expr ()
{
return 0;
}
int
recognize_objc_keyword ()
{
return 0;
}
tree
build_objc_string (len, str)
int len;
char *str;
{
abort ();
return NULL_TREE;
}
void
GNU_xref_begin ()
{
fatal ("GCC does not yet support XREF");
}
void
GNU_xref_end ()
{
fatal ("GCC does not yet support XREF");
}

1983
gnu/usr.bin/cc/cc1/c-lex.c Normal file

File diff suppressed because it is too large Load Diff

3530
gnu/usr.bin/cc/cc1/c-parse.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,188 @@
/* Handle #pragma, system V.4 style. Supports #pragma weak and #pragma pack.
Copyright (C) 1992 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include "config.h"
#include "tree.h"
#include "function.h"
#include "defaults.h"
#ifdef HANDLE_SYSV_PRAGMA
/* Support #pragma weak by default if WEAK_ASM_OP and ASM_OUTPUT_DEF
are defined. */
#if !defined (HANDLE_PRAGMA_WEAK) && defined (WEAK_ASM_OP) && defined (ASM_OUTPUT_DEF)
#define HANDLE_PRAGMA_WEAK 1
#endif
/* See varasm.c for an identical definition. */
enum pragma_state
{
ps_start,
ps_done,
ps_bad,
ps_weak,
ps_name,
ps_equals,
ps_value,
ps_pack,
ps_left,
ps_align,
ps_right
};
/* When structure field packing is in effect, this variable is the
number of bits to use as the maximum alignment. When packing is not
in effect, this is zero. */
extern int maximum_field_alignment;
/* File used for outputting assembler code. */
extern FILE *asm_out_file;
/* Handle one token of a pragma directive. TOKEN is the
current token, and STRING is its printable form. */
void
handle_pragma_token (string, token)
char *string;
tree token;
{
static enum pragma_state state = ps_start, type;
static char *name;
static char *value;
static int align;
if (string == 0)
{
if (type == ps_pack)
{
if (state == ps_right)
maximum_field_alignment = align * 8;
else
warning ("malformed `#pragma pack'");
}
else if (type == ps_weak)
{
#ifdef HANDLE_PRAGMA_WEAK
if (HANDLE_PRAGMA_WEAK)
handle_pragma_weak (state, asm_out_file, name, value);
#endif /* HANDLE_PRAMA_WEAK */
}
type = state = ps_start;
return;
}
switch (state)
{
case ps_start:
if (token && TREE_CODE (token) == IDENTIFIER_NODE)
{
if (strcmp (IDENTIFIER_POINTER (token), "pack") == 0)
type = state = ps_pack;
else if (strcmp (IDENTIFIER_POINTER (token), "weak") == 0)
type = state = ps_weak;
else
type = state = ps_done;
}
else
type = state = ps_done;
break;
case ps_weak:
if (token && TREE_CODE (token) == IDENTIFIER_NODE)
{
name = IDENTIFIER_POINTER (token);
state = ps_name;
}
else
state = ps_bad;
break;
case ps_name:
state = (strcmp (string, "=") ? ps_bad : ps_equals);
break;
case ps_equals:
if (token && TREE_CODE (token) == IDENTIFIER_NODE)
{
value = IDENTIFIER_POINTER (token);
state = ps_value;
}
else
state = ps_bad;
break;
case ps_value:
state = ps_bad;
break;
case ps_pack:
if (strcmp (string, "(") == 0)
state = ps_left;
else
state = ps_bad;
break;
case ps_left:
if (token && TREE_CODE (token) == INTEGER_CST
&& TREE_INT_CST_HIGH (token) == 0)
switch (TREE_INT_CST_LOW (token))
{
case 1:
case 2:
case 4:
align = TREE_INT_CST_LOW (token);
state = ps_align;
break;
default:
state = ps_bad;
}
else if (! token && strcmp (string, ")") == 0)
{
align = 0;
state = ps_right;
}
else
state = ps_bad;
break;
case ps_align:
if (strcmp (string, ")") == 0)
state = ps_right;
else
state = ps_bad;
break;
case ps_right:
state = ps_bad;
break;
case ps_bad:
case ps_done:
break;
default:
abort ();
}
}
#endif /* HANDLE_SYSV_PRAGMA */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
#
# $FreeBSD$
#
PROG = cc1plus
SRCS = call.c class.c cvt.c decl.c decl2.c edsel.c errfn.c error.c except.c expr.c gc.c init.c lex.c method.c parse.c pt.c ptree.c search.c sig.c spew.c tree.c typeck.c typeck2.c xref.c
BINDIR= /usr/libexec
NOMAN= 1
LDDESTDIR+= -L${.CURDIR}/../cc_int/obj
LDDESTDIR+= -L${.CURDIR}/../cc_int
LDADD+= -lcc_int
.include <bsd.prog.mk>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,116 @@
/* Variables and structures for overloading rules.
Copyright (C) 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* The following structure is used when comparing various alternatives
for overloading. The unsigned quantity `strikes.i' is used
for fast comparison of two possibilities. This number is an
aggregate of four constituents:
EVIL: if this is non-zero, then the candidate should not be considered
ELLIPSIS: if this is non-zero, then some actual argument has been matched
against an ellipsis
USER: if this is non-zero, then a user-defined type conversion is needed
B_OR_D: if this is non-zero, then use a base pointer instead of the
type of the pointer we started with.
EASY: if this is non-zero, then we have a builtin conversion
(such as int to long, int to float, etc) to do.
If two candidates require user-defined type conversions, and the
type conversions are not identical, then an ambiguity error
is reported.
If two candidates agree on user-defined type conversions,
and one uses pointers of strictly higher type (derived where
another uses base), then that alternative is silently chosen.
Note that this technique really only works for 255 arguments. Perhaps
this is not enough. */
/* These macros and harshness_code are used by the NEW METHOD. */
#define EVIL_CODE (1<<7)
#define CONST_CODE (1<<6)
#define ELLIPSIS_CODE (1<<5)
#define USER_CODE (1<<4)
#define STD_CODE (1<<3)
#define PROMO_CODE (1<<2)
#define QUAL_CODE (1<<1)
#define TRIVIAL_CODE (1<<0)
struct harshness_code
{
/* What kind of conversion is involved. */
unsigned short code;
/* The inheritance distance. */
short distance;
/* For a PROMO_CODE, Any special penalties involved in integral conversions.
This exists because $4.1 of the ARM states that something like
`short unsigned int' should promote to `int', not `unsigned int'.
If, for example, it tries to match two fns, f(int) and f(unsigned),
f(int) should be a better match than f(unsigned) by this rule. Without
this extra metric, they both only appear as "integral promotions", which
will lead to an ambiguity.
For a TRIVIAL_CODE, This is also used by build_overload_call_real and
convert_harshness to keep track of other information we need. */
unsigned short int_penalty;
};
struct candidate
{
struct harshness_code h; /* Used for single-argument conversions. */
int h_len; /* The length of the harshness vector. */
tree function; /* A FUNCTION_DECL */
tree basetypes; /* The path to function. */
tree arg; /* first parm to function. */
/* Indexed by argument number, encodes evil, user, d_to_b, and easy
strikes for that argument. At end of array, we store the index+1
of where we started using default parameters, or 0 if there are
none. */
struct harshness_code *harshness;
union
{
tree field; /* If no evil strikes, the FUNCTION_DECL of
the function (if a member function). */
int bad_arg; /* the index of the first bad argument:
0 if no bad arguments
> 0 is first bad argument
-1 if extra actual arguments
-2 if too few actual arguments.
-3 if const/non const method mismatch.
-4 if type unification failed.
-5 if contravariance violation. */
} u;
};
int rank_for_overload ();
/* Variables shared between class.c and call.c. */
extern int n_vtables;
extern int n_vtable_entries;
extern int n_vtable_searches;
extern int n_vtable_elems;
extern int n_convert_harshness;
extern int n_compute_conversion_costs;
extern int n_build_method_call;
extern int n_inner_fields_searched;

File diff suppressed because it is too large Load Diff

2044
gnu/usr.bin/cc/cc1plus/cvt.c Normal file

File diff suppressed because it is too large Load Diff

12030
gnu/usr.bin/cc/cc1plus/decl.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
/* Variables and structures for declaration processing.
Copyright (C) 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* In grokdeclarator, distinguish syntactic contexts of declarators. */
enum decl_context
{ NORMAL, /* Ordinary declaration */
FUNCDEF, /* Function definition */
PARM, /* Declaration of parm before function body */
FIELD, /* Declaration inside struct or union */
BITFIELD, /* Likewise but with specified width */
TYPENAME, /* Typename (inside cast or sizeof) */
MEMFUNCDEF /* Member function definition */
};
/* C++: Keep these around to reduce calls to `get_identifier'.
Identifiers for `this' in member functions and the auto-delete
parameter for destructors. */
extern tree this_identifier, in_charge_identifier;
/* Parsing a function declarator leaves a list of parameter names
or a chain or parameter decls here. */
extern tree last_function_parms;
/* A list of static class variables. This is needed, because a
static class variable can be declared inside the class without
an initializer, and then initialized, staticly, outside the class. */
extern tree pending_statics;
/* A list of objects which have constructors or destructors
which reside in the global scope. The decl is stored in
the TREE_VALUE slot and the initializer is stored
in the TREE_PURPOSE slot. */
extern tree static_aggregates;
#ifdef DEBUG_CP_BINDING_LEVELS
/* Purely for debugging purposes. */
extern int debug_bindings_indentation;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,927 @@
/* Interface to LUCID Cadillac system for GNU compiler.
Copyright (C) 1988, 1992, 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include "tree.h"
#include "flags.h"
#include <stdio.h>
#include "cp-tree.h"
#include "obstack.h"
#ifdef CADILLAC
#include <compilerreq.h>
#include <compilerconn.h>
#include <sys/time.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/file.h>
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
void init_cadillac ();
extern char *input_filename;
extern int lineno;
/* Put random information we might want to get back from
Cadillac here. */
typedef struct
{
/* The connection to the Cadillac kernel. */
Connection *conn;
/* Input and output file descriptors for Cadillac. */
short fd_input, fd_output;
/* #include nesting of current file. */
short depth;
/* State variables for the connection. */
char messages;
char conversion;
char emission;
char process_until;
/* #if level of current file. */
int iflevel;
/* Line number that starts current source file. */
int lineno;
/* Name of current file. */
char *filename;
/* Where to stop processing (if process_until is set). */
char *end_filename;
int end_position;
} cadillac_struct;
static cadillac_struct cadillacObj;
/* Nonzero if in the process of exiting. */
static int exiting;
void cadillac_note_source ();
static void CWriteLanguageDecl ();
static void CWriteLanguageType ();
static void CWriteTopLevel ();
static void cadillac_note_filepos ();
static void cadillac_process_request (), cadillac_process_requests ();
static void cadillac_switch_source ();
static void exit_cadillac ();
/* Blocking test. */
static int
readable_p (fd)
int fd;
{
fd_set f;
FD_ZERO (&f);
FD_SET (fd, &f);
return select (32, &f, NULL, NULL, 0) == 1;
}
static CObjectType *tree_to_cadillac_map;
struct obstack cadillac_obstack;
#include "stack.h"
struct context_level
{
struct stack_level base;
tree context;
};
/* Stack for maintaining contexts (in case functions or types are nested).
When defining a struct type, the `context' field is the RECORD_TYPE.
When defining a function, the `context' field is the FUNCTION_DECL. */
static struct context_level *context_stack;
static struct context_level *
push_context_level (stack, obstack)
struct stack_level *stack;
struct obstack *obstack;
{
struct context_level tem;
tem.base.prev = stack;
return (struct context_level *)push_stack_level (obstack, &tem, sizeof (tem));
}
/* Discard a level of search allocation. */
static struct context_level *
pop_context_level (stack)
struct context_level *stack;
{
stack = (struct context_level *)pop_stack_level (stack);
return stack;
}
void
init_cadillac ()
{
extern FILE *finput;
extern int errno;
CCompilerMessage* req;
cadillac_struct *cp = &cadillacObj;
int i;
if (! flag_cadillac)
return;
tree_to_cadillac_map = (CObjectType*) xmalloc (sizeof (CObjectType) * LAST_CPLUS_TREE_CODE);
for (i = 0; i < LAST_CPLUS_TREE_CODE; i++)
tree_to_cadillac_map[i] = MiscOType;
tree_to_cadillac_map[RECORD_TYPE] = StructOType;
tree_to_cadillac_map[UNION_TYPE] = UnionOType;
tree_to_cadillac_map[ENUMERAL_TYPE] = EnumTypeOType;
tree_to_cadillac_map[TYPE_DECL] = TypedefOType;
tree_to_cadillac_map[VAR_DECL] = VariableOType;
tree_to_cadillac_map[CONST_DECL] = EnumConstantOType;
tree_to_cadillac_map[FUNCTION_DECL] = FunctionOType;
tree_to_cadillac_map[FIELD_DECL] = FieldOType;
#ifdef sun
on_exit (&exit_cadillac, 0);
#endif
gcc_obstack_init (&cadillac_obstack);
/* Yow! This is the way Cadillac was designed to deal with
Oregon C++ compiler! */
cp->fd_input = flag_cadillac;
cp->fd_output = flag_cadillac;
/* Start in "turned-on" state. */
cp->messages = 1;
cp->conversion = 1;
cp->emission = 1;
/* Establish a connection with Cadillac here. */
cp->conn = NewConnection (cp, cp->fd_input, cp->fd_output);
CWriteHeader (cp->conn, WaitingMType, 0);
CWriteRequestBuffer (cp->conn);
if (!readable_p (cp->fd_input))
;
req = CReadCompilerMessage (cp->conn);
if (!req)
switch (errno)
{
case EWOULDBLOCK:
sleep (5);
return;
case 0:
fatal ("init_cadillac: EOF on connection to kernel, exiting\n");
break;
default:
perror ("Editor to kernel connection");
exit (0);
}
}
static void
cadillac_process_requests (conn)
Connection *conn;
{
CCompilerMessage *req;
while (req = (CCompilerMessage*) CPeekNextRequest (conn))
{
req = CReadCompilerMessage (conn);
cadillac_process_request (&cadillacObj, req);
}
}
static void
cadillac_process_request (cp, req)
cadillac_struct *cp;
CCompilerMessage *req;
{
if (! req)
return;
switch (req->reqType)
{
case ProcessUntilMType:
if (cp->process_until)
my_friendly_abort (23);
cp->process_until = 1;
/* This is not really right. */
cp->end_position = ((CCompilerCommand*)req)->processuntil.position;
#if 0
cp->end_filename = req->processuntil.filename;
#endif
break;
case CommandMType:
switch (req->header.data)
{
case MessagesOnCType:
cp->messages = 1;
break;
case MessagesOffCType:
cp->messages = 0;
break;
case ConversionOnCType:
cp->conversion = 1;
break;
case ConversionOffCType:
cp->conversion = 0;
break;
case EmissionOnCType:
cp->emission = 1;
break;
case EmissionOffCType:
cp->emission = 0;
break;
case FinishAnalysisCType:
return;
case PuntAnalysisCType:
case ContinueAnalysisCType:
case GotoFileposCType:
case OpenSucceededCType:
case OpenFailedCType:
fprintf (stderr, "request type %d not implemented\n", req->reqType);
return;
case DieCType:
if (! exiting)
my_friendly_abort (24);
return;
}
break;
default:
fatal ("unknown request type %d", req->reqType);
}
}
void
cadillac_start ()
{
Connection *conn = cadillacObj.conn;
CCompilerMessage *req;
/* Let Cadillac know that we start in C++ language scope. */
CWriteHeader (conn, ForeignLinkageMType, LinkCPlus);
CWriteLength (conn);
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
static void
cadillac_printf (msg, name)
{
if (cadillacObj.messages)
printf ("[%s,%4d] %s `%s'\n", input_filename, lineno, msg, name);
}
void
cadillac_start_decl (decl)
tree decl;
{
Connection *conn = cadillacObj.conn;
CObjectType object_type = tree_to_cadillac_map [TREE_CODE (decl)];
if (context_stack)
switch (TREE_CODE (context_stack->context))
{
case FUNCTION_DECL:
/* Currently, cadillac only implements top-level forms. */
return;
case RECORD_TYPE:
case UNION_TYPE:
cadillac_printf ("start class-level decl", IDENTIFIER_POINTER (DECL_NAME (decl)));
break;
default:
my_friendly_abort (25);
}
else
{
cadillac_printf ("start top-level decl", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
CWriteTopLevel (conn, StartMType);
}
CWriteLanguageDecl (conn, decl, tree_to_cadillac_map[TREE_CODE (decl)]);
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
void
cadillac_finish_decl (decl)
tree decl;
{
Connection *conn = cadillacObj.conn;
if (context_stack)
switch (TREE_CODE (context_stack->context))
{
case FUNCTION_DECL:
return;
case RECORD_TYPE:
case UNION_TYPE:
cadillac_printf ("end class-level decl", IDENTIFIER_POINTER (DECL_NAME (decl)));
CWriteHeader (conn, EndDefMType, 0);
CWriteLength (conn);
break;
default:
my_friendly_abort (26);
}
else
{
cadillac_printf ("end top-level decl", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
CWriteHeader (conn, EndDefMType, 0);
CWriteLength (conn);
CWriteTopLevel (conn, StopMType);
}
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
void
cadillac_start_function (fndecl)
tree fndecl;
{
Connection *conn = cadillacObj.conn;
if (context_stack)
/* nested functions not yet handled. */
my_friendly_abort (27);
cadillac_printf ("start top-level function", lang_printable_name (fndecl));
context_stack = push_context_level (context_stack, &cadillac_obstack);
context_stack->context = fndecl;
CWriteTopLevel (conn, StartMType);
my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 202);
CWriteLanguageDecl (conn, fndecl,
(TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE
? MemberFnOType : FunctionOType));
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
void
cadillac_finish_function (fndecl)
tree fndecl;
{
Connection *conn = cadillacObj.conn;
cadillac_printf ("end top-level function", lang_printable_name (fndecl));
context_stack = pop_context_level (context_stack);
if (context_stack)
/* nested functions not yet implemented. */
my_friendly_abort (28);
CWriteHeader (conn, EndDefMType, 0);
CWriteLength (conn);
CWriteTopLevel (conn, StopMType);
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
void
cadillac_finish_anon_union (decl)
tree decl;
{
Connection *conn = cadillacObj.conn;
if (! global_bindings_p ())
return;
cadillac_printf ("finish top-level anon union", "");
CWriteHeader (conn, EndDefMType, 0);
CWriteLength (conn);
CWriteTopLevel (conn, StopMType);
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
void
cadillac_start_enum (type)
tree type;
{
Connection *conn = cadillacObj.conn;
tree name = TYPE_NAME (type);
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
if (context_stack)
switch (TREE_CODE (context_stack->context))
{
case FUNCTION_DECL:
return;
case RECORD_TYPE:
case UNION_TYPE:
break;
default:
my_friendly_abort (29);
}
else
{
cadillac_printf ("start top-level enum", IDENTIFIER_POINTER (name));
CWriteTopLevel (conn, StartMType);
}
CWriteLanguageType (conn, type, tree_to_cadillac_map[ENUMERAL_TYPE]);
}
void
cadillac_finish_enum (type)
tree type;
{
Connection *conn = cadillacObj.conn;
tree name = TYPE_NAME (type);
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
if (context_stack)
switch (TREE_CODE (context_stack->context))
{
case FUNCTION_DECL:
return;
case RECORD_TYPE:
case UNION_TYPE:
CWriteHeader (conn, EndDefMType, 0);
CWriteLength (conn);
break;
default:
my_friendly_abort (30);
}
else
{
CWriteHeader (conn, EndDefMType, 0);
CWriteLength (conn);
cadillac_printf ("finish top-level enum", IDENTIFIER_POINTER (name));
CWriteTopLevel (conn, StopMType);
}
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
void
cadillac_start_struct (type)
tree type;
{
Connection *conn = cadillacObj.conn;
tree name = TYPE_NAME (type);
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
if (context_stack)
switch (TREE_CODE (context_stack->context))
{
case FUNCTION_DECL:
return;
case RECORD_TYPE:
case UNION_TYPE:
return;
default:
my_friendly_abort (31);
}
else
{
cadillac_printf ("start struct", IDENTIFIER_POINTER (name));
CWriteTopLevel (conn, StartMType);
}
context_stack = push_context_level (context_stack, &cadillac_obstack);
context_stack->context = type;
CWriteLanguageType (conn, type,
TYPE_LANG_SPECIFIC (type) && CLASSTYPE_DECLARED_CLASS (type) ? ClassOType : tree_to_cadillac_map[TREE_CODE (type)]);
}
void
cadillac_finish_struct (type)
tree type;
{
Connection *conn = cadillacObj.conn;
tree name = TYPE_NAME (type);
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
context_stack = pop_context_level (context_stack);
if (context_stack)
return;
cadillac_printf ("finish struct", IDENTIFIER_POINTER (name));
CWriteHeader (conn, EndDefMType, 0);
CWriteLength (conn);
CWriteTopLevel (conn, StopMType);
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
void
cadillac_finish_exception (type)
tree type;
{
Connection *conn = cadillacObj.conn;
fatal ("cadillac_finish_exception");
CWriteHeader (conn, EndDefMType, 0);
CWriteLength (conn);
CWriteTopLevel (conn, StopMType);
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
void
cadillac_push_class (type)
tree type;
{
}
void
cadillac_pop_class ()
{
}
void
cadillac_push_lang (name)
tree name;
{
Connection *conn = cadillacObj.conn;
CLinkLanguageType m;
if (name == lang_name_cplusplus)
m = LinkCPlus;
else if (name == lang_name_c)
m = LinkC;
else
my_friendly_abort (32);
CWriteHeader (conn, ForeignLinkageMType, m);
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
void
cadillac_pop_lang ()
{
Connection *conn = cadillacObj.conn;
CWriteHeader (conn, ForeignLinkageMType, LinkPop);
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
void
cadillac_finish_stmt ()
{
}
void
cadillac_note_source ()
{
cadillacObj.lineno = lineno;
cadillacObj.filename = input_filename;
}
static void
CWriteTopLevel (conn, m)
Connection *conn;
CMessageSubType m;
{
static context_id = 0;
CWriteHeader (conn, TopLevelFormMType, m);
cadillac_note_filepos ();
/* Eventually, this will point somewhere into the digest file. */
context_id += 1;
CWriteSomething (conn, &context_id, sizeof (BITS32));
CWriteSomething (conn, &cadillacObj.iflevel, sizeof (BITS32));
CWriteLength (conn);
}
static void
cadillac_note_filepos ()
{
extern FILE *finput;
int pos = ftell (finput);
CWriteSomething (cadillacObj.conn, &pos, sizeof (BITS32));
}
void
cadillac_switch_source (startflag)
int startflag;
{
Connection *conn = cadillacObj.conn;
/* Send out the name of the source file being compiled. */
CWriteHeader (conn, SourceFileMType, startflag ? StartMType : StopMType);
CWriteSomething (conn, &cadillacObj.depth, sizeof (BITS16));
CWriteVstring0 (conn, input_filename);
CWriteLength (conn);
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
void
cadillac_push_source ()
{
cadillacObj.depth += 1;
cadillac_switch_source (1);
}
void
cadillac_pop_source ()
{
cadillacObj.depth -= 1;
cadillac_switch_source (0);
}
struct cadillac_mdep
{
short object_type;
char linkage;
char access;
short length;
};
static void
CWriteLanguageElem (conn, p, name)
Connection *conn;
struct cadillac_mdep *p;
char *name;
{
CWriteSomething (conn, &p->object_type, sizeof (BITS16));
CWriteSomething (conn, &p->linkage, sizeof (BITS8));
CWriteSomething (conn, &p->access, sizeof (BITS8));
CWriteSomething (conn, &p->length, sizeof (BITS16));
CWriteVstring0 (conn, name);
#if 0
/* Don't write date_type. */
CWriteVstring0 (conn, "");
#endif
CWriteLength (conn);
}
static void
CWriteLanguageDecl (conn, decl, object_type)
Connection *conn;
tree decl;
CObjectType object_type;
{
struct cadillac_mdep foo;
tree name;
CWriteHeader (conn, LanguageElementMType, StartDefineMType);
foo.object_type = object_type;
if (decl_type_context (decl))
{
foo.linkage = ParentLinkage;
if (TREE_PRIVATE (decl))
foo.access = PrivateAccess;
else if (TREE_PROTECTED (decl))
foo.access = ProtectedAccess;
else
foo.access = PublicAccess;
}
else
{
if (TREE_PUBLIC (decl))
foo.linkage = GlobalLinkage;
else
foo.linkage = FileLinkage;
foo.access = PublicAccess;
}
name = DECL_NAME (decl);
foo.length = IDENTIFIER_LENGTH (name);
CWriteLanguageElem (conn, &foo, IDENTIFIER_POINTER (name));
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
static void
CWriteLanguageType (conn, type, object_type)
Connection *conn;
tree type;
CObjectType object_type;
{
struct cadillac_mdep foo;
tree name = TYPE_NAME (type);
CWriteHeader (conn, LanguageElementMType, StartDefineMType);
foo.object_type = object_type;
if (current_class_type)
{
foo.linkage = ParentLinkage;
if (TREE_PRIVATE (type))
foo.access = PrivateAccess;
else if (TREE_PROTECTED (type))
foo.access = ProtectedAccess;
else
foo.access = PublicAccess;
}
else
{
foo.linkage = NoLinkage;
foo.access = PublicAccess;
}
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
foo.length = IDENTIFIER_LENGTH (name);
CWriteLanguageElem (conn, &foo, IDENTIFIER_POINTER (name));
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
static void
CWriteUseObject (conn, type, object_type, use)
Connection *conn;
tree type;
CObjectType object_type;
CMessageSubType use;
{
struct cadillac_mdep foo;
tree name = NULL_TREE;
CWriteHeader (conn, LanguageElementMType, use);
foo.object_type = object_type;
if (current_class_type)
{
foo.linkage = ParentLinkage;
if (TREE_PRIVATE (type))
foo.access = PrivateAccess;
else if (TREE_PROTECTED (type))
foo.access = ProtectedAccess;
else
foo.access = PublicAccess;
}
else
{
foo.linkage = NoLinkage;
foo.access = PublicAccess;
}
switch (TREE_CODE (type))
{
case VAR_DECL:
case FIELD_DECL:
case TYPE_DECL:
case CONST_DECL:
case FUNCTION_DECL:
name = DECL_NAME (type);
break;
default:
my_friendly_abort (33);
}
foo.length = IDENTIFIER_LENGTH (name);
CWriteLanguageElem (conn, &foo, IDENTIFIER_POINTER (name));
CWriteRequestBuffer (conn);
cadillac_process_requests (conn);
}
/* Here's how we exit under cadillac. */
static void
exit_cadillac ()
{
extern int errorcount;
Connection *conn = cadillacObj.conn;
if (flag_cadillac)
{
CCompilerMessage *req;
CWriteHeader (conn, FinishedMType,
errorcount ? 0 : CsObjectWritten | CsComplete);
/* Bye, bye! */
CWriteRequestBuffer (conn);
/* Block on read. */
while (! readable_p (cadillacObj.fd_input))
{
if (exiting)
my_friendly_abort (34);
exiting = 1;
}
exiting = 1;
req = CReadCompilerMessage (conn);
cadillac_process_request (&cadillacObj, req);
}
}
#else
/* Stubs. */
void init_cadillac () {}
void cadillac_start () {}
void cadillac_start_decl (decl)
tree decl;
{}
void
cadillac_finish_decl (decl)
tree decl;
{}
void
cadillac_start_function (fndecl)
tree fndecl;
{}
void
cadillac_finish_function (fndecl)
tree fndecl;
{}
void
cadillac_finish_anon_union (decl)
tree decl;
{}
void
cadillac_start_enum (type)
tree type;
{}
void
cadillac_finish_enum (type)
tree type;
{}
void
cadillac_start_struct (type)
tree type;
{}
void
cadillac_finish_struct (type)
tree type;
{}
void
cadillac_finish_exception (type)
tree type;
{}
void
cadillac_push_class (type)
tree type;
{}
void
cadillac_pop_class ()
{}
void
cadillac_push_lang (name)
tree name;
{}
void
cadillac_pop_lang ()
{}
void
cadillac_note_source ()
{}
void
cadillac_finish_stmt ()
{}
void
cadillac_switch_source ()
{}
void
cadillac_push_source ()
{}
void
cadillac_pop_source ()
{}
#endif

View File

@ -0,0 +1,217 @@
/* Provide a call-back mechanism for handling error output.
Copyright (C) 1993 Free Software Foundation, Inc.
Contributed by Jason Merrill (jason@cygnus.com)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include "tree.h"
#include <ctype.h>
/* cp_printer is the type of a function which converts an argument into
a string for digestion by printf. The cp_printer function should deal
with all memory management; the functions in this file will not free
the char*s returned. See error.c for an example use of this code. */
typedef char* cp_printer PROTO((HOST_WIDE_INT, int));
extern cp_printer * cp_printers[256];
typedef void errorfn (); /* deliberately vague */
extern char* cp_file_of PROTO((tree));
extern int cp_line_of PROTO((tree));
#define STRDUP(f) (ap = (char *) alloca (strlen (f) +1), strcpy (ap, (f)), ap)
#define NARGS 3
#define arglist a1, a2, a3
#define arglist_dcl HOST_WIDE_INT a1, a2, a3;
#define ARGSINIT args[0] = a1; args[1] = a2; args[2] = a3;
#define ARGSLIST args[0], args[1], args[2]
static void
cp_thing (errfn, atarg1, format, arglist)
errorfn *errfn;
int atarg1;
char *format;
arglist_dcl
{
char *fmt;
char *f;
char *ap;
int arg;
HOST_WIDE_INT atarg = atarg1 ? a1 : 0;
HOST_WIDE_INT args[NARGS];
ARGSINIT
fmt = STRDUP(format);
for (f = fmt, arg = 0; *f; ++f)
{
cp_printer * function;
int alternate;
int maybe_here;
/* ignore text */
if (*f != '%') continue;
++f;
alternate = 0;
maybe_here = 0;
/* ignore most flags */
while (*f == ' ' || *f == '-' || *f == '+' || *f == '#')
{
if (*f == '+')
maybe_here = 1;
else if (*f == '#')
alternate = 1;
++f;
}
/* ignore field width */
if (*f == '*')
{
++f;
++arg;
}
else
while (isdigit (*f))
++f;
/* ignore precision */
if (*f == '.')
{
++f;
if (*f == '*')
{
++f;
++arg;
}
else
while (isdigit (*f))
++f;
}
/* ignore "long" */
if (*f == 'l')
++f;
function = cp_printers[(int)*f];
if (function)
{
char *p;
if (arg >= NARGS) abort ();
if (maybe_here && atarg1)
atarg = args[arg];
/* Must use a temporary to avoid calling *function twice */
p = (*function) (args[arg], alternate);
args[arg] = (HOST_WIDE_INT) STRDUP(p);
*f = 's';
}
++arg; /* Assume valid format string */
}
if (atarg)
{
char *file = cp_file_of ((tree) atarg);
int line = cp_line_of ((tree) atarg);
(*errfn) (file, line, fmt, ARGSLIST);
}
else
(*errfn) (fmt, ARGSLIST);
}
void
cp_error (format, arglist)
char *format;
arglist_dcl
{
extern errorfn error;
cp_thing (error, 0, format, arglist);
}
void
cp_warning (format, arglist)
char *format;
arglist_dcl
{
extern errorfn warning;
cp_thing (warning, 0, format, arglist);
}
void
cp_pedwarn (format, arglist)
char *format;
arglist_dcl
{
extern errorfn pedwarn;
cp_thing (pedwarn, 0, format, arglist);
}
void
cp_compiler_error (format, arglist)
char *format;
arglist_dcl
{
extern errorfn compiler_error;
cp_thing (compiler_error, 0, format, arglist);
}
void
cp_sprintf (format, arglist)
char *format;
arglist_dcl
{
extern errorfn sprintf;
cp_thing (sprintf, 0, format, arglist);
}
void
cp_error_at (format, arglist)
char *format;
arglist_dcl
{
extern errorfn error_with_file_and_line;
cp_thing (error_with_file_and_line, 1, format, arglist);
}
void
cp_warning_at (format, arglist)
char *format;
arglist_dcl
{
extern errorfn warning_with_file_and_line;
cp_thing (warning_with_file_and_line, 1, format, arglist);
}
void
cp_pedwarn_at (format, arglist)
char *format;
arglist_dcl
{
extern errorfn pedwarn_with_file_and_line;
cp_thing (pedwarn_with_file_and_line, 1, format, arglist);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,275 @@
/* Convert language-specific tree expression to rtl instructions,
for GNU compiler.
Copyright (C) 1988, 1992, 1993 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
#include "expr.h"
#include "cp-tree.h"
#undef NULL
#define NULL 0
/* Hook used by expand_expr to expand language-specific tree codes. */
rtx
cplus_expand_expr (exp, target, tmode, modifier)
tree exp;
rtx target;
enum machine_mode tmode;
enum expand_modifier modifier;
{
tree type = TREE_TYPE (exp);
register enum machine_mode mode = TYPE_MODE (type);
register enum tree_code code = TREE_CODE (exp);
rtx original_target = target;
int ignore = target == const0_rtx;
if (ignore)
target = 0, original_target = 0;
/* No sense saving up arithmetic to be done
if it's all in the wrong mode to form part of an address.
And force_operand won't know whether to sign-extend or zero-extend. */
if (mode != Pmode && modifier == EXPAND_SUM)
modifier = EXPAND_NORMAL;
switch (code)
{
case NEW_EXPR:
{
/* Something needs to be initialized, but we didn't know
where that thing was when building the tree. For example,
it could be the return value of a function, or a parameter
to a function which lays down in the stack, or a temporary
variable which must be passed by reference.
Cleanups are handled in a language-specific way: they
might be run by the called function (true in GNU C++
for parameters with cleanups), or they might be
run by the caller, after the call (true in GNU C++
for other cleanup needs). */
tree func = TREE_OPERAND (exp, 0);
tree args = TREE_OPERAND (exp, 1);
tree type = TREE_TYPE (exp), slot;
tree fn_type = TREE_TYPE (TREE_TYPE (func));
tree return_type = TREE_TYPE (fn_type);
tree call_exp;
rtx call_target, return_target;
int pcc_struct_return = 0;
/* The expression `init' wants to initialize what
`target' represents. SLOT holds the slot for TARGET. */
slot = TREE_OPERAND (exp, 2);
if (target == 0)
{
/* Should always be called with a target in BLKmode case. */
my_friendly_assert (mode != BLKmode, 205);
my_friendly_assert (DECL_RTL (slot) != 0, 206);
target = gen_reg_rtx (mode);
}
/* The target the initializer will initialize (CALL_TARGET)
must now be directed to initialize the target we are
supposed to initialize (TARGET). The semantics for
choosing what CALL_TARGET is is language-specific,
as is building the call which will perform the
initialization. It is left here to show the choices that
exist for C++. */
if (TREE_CODE (func) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (func, 0)) == FUNCTION_DECL
&& DECL_CONSTRUCTOR_P (TREE_OPERAND (func, 0)))
{
type = TYPE_POINTER_TO (type);
/* Don't clobber a value that might be part of a default
parameter value. */
if (TREE_PERMANENT (args))
args = tree_cons (0, build1 (ADDR_EXPR, type, slot),
TREE_CHAIN (args));
else
TREE_VALUE (args) = build1 (ADDR_EXPR, type, slot);
call_target = 0;
}
else if (TREE_CODE (return_type) == REFERENCE_TYPE)
{
type = return_type;
call_target = 0;
}
else
{
#ifdef PCC_STATIC_STRUCT_RETURN
pcc_struct_return = 1;
call_target = 0;
#else
call_target = target;
#endif
}
if (call_target)
{
preserve_temp_slots (call_target);
/* Make this a valid memory address now. The code below assumes
that it can compare rtx and make assumptions based on the
result. The assumptions are true only if the address was
valid to begin with. */
call_target = validize_mem (call_target);
}
preserve_temp_slots (DECL_RTL (slot));
call_exp = build (CALL_EXPR, type, func, args, 0);
TREE_SIDE_EFFECTS (call_exp) = 1;
return_target = expand_expr (call_exp, call_target, mode, 0);
free_temp_slots ();
if (call_target == 0)
{
if (pcc_struct_return)
{
tree init = build (RTL_EXPR, type, 0, return_target);
TREE_ADDRESSABLE (init) = 1;
expand_aggr_init (slot, init, 0);
if (TYPE_NEEDS_DESTRUCTOR (type))
{
init = build (RTL_EXPR, build_reference_type (type), 0,
XEXP (return_target, 0));
init = maybe_build_cleanup (convert_from_reference (init));
if (init != NULL_TREE)
expand_expr (init, 0, 0, 0);
}
call_target = return_target = DECL_RTL (slot);
}
else
call_target = return_target;
}
if (call_target != return_target)
{
my_friendly_assert (! TYPE_NEEDS_CONSTRUCTING (type), 317);
if (GET_MODE (return_target) == BLKmode)
emit_block_move (call_target, return_target, expr_size (exp),
TYPE_ALIGN (type) / BITS_PER_UNIT);
else
emit_move_insn (call_target, return_target);
}
if (TREE_CODE (return_type) == REFERENCE_TYPE)
{
tree init;
if (GET_CODE (call_target) == REG
&& REGNO (call_target) < FIRST_PSEUDO_REGISTER)
my_friendly_abort (39);
type = TREE_TYPE (exp);
init = build (RTL_EXPR, return_type, 0, call_target);
/* We got back a reference to the type we want. Now initialize
target with that. */
expand_aggr_init (slot, init, 0);
}
if (DECL_RTL (slot) != target)
emit_move_insn (DECL_RTL (slot), target);
return DECL_RTL (slot);
}
case OFFSET_REF:
{
#if 1
return expand_expr (default_conversion (resolve_offset_ref (exp)),
target, tmode, EXPAND_NORMAL);
#else
/* This is old crusty code, and does not handle all that the
resolve_offset_ref function does. (mrs) */
tree base = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 0), 0);
tree offset = build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 1), 0);
return expand_expr (build (PLUS_EXPR, TREE_TYPE (exp), base, offset),
target, tmode, EXPAND_NORMAL);
#endif
}
case THUNK_DECL:
return DECL_RTL (exp);
case THROW_EXPR:
expand_throw (TREE_OPERAND (exp, 0));
return NULL;
default:
break;
}
my_friendly_abort (40);
/* NOTREACHED */
return NULL;
}
void
init_cplus_expand ()
{
lang_expand_expr = cplus_expand_expr;
}
/* If DECL had its rtl moved from where callers expect it
to be, fix it up. RESULT is the nominal rtl for the RESULT_DECL,
which may be a pseudo instead of a hard register. */
void
fixup_result_decl (decl, result)
tree decl;
rtx result;
{
if (REG_P (result))
{
if (REGNO (result) >= FIRST_PSEUDO_REGISTER)
{
rtx real_decl_result;
#ifdef FUNCTION_OUTGOING_VALUE
real_decl_result
= FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl), current_function_decl);
#else
real_decl_result
= FUNCTION_VALUE (TREE_TYPE (decl), current_function_decl);
#endif
REG_FUNCTION_VALUE_P (real_decl_result) = 1;
result = real_decl_result;
}
emit_move_insn (result, DECL_RTL (decl));
emit_insn (gen_rtx (USE, VOIDmode, result));
}
}
/* Return nonzero iff DECL is memory-based. The DECL_RTL of
certain const variables might be a CONST_INT, or a REG
in some cases. We cannot use `memory_operand' as a test
here because on most RISC machines, a variable's address
is not, by itself, a legitimate address. */
int
decl_in_memory_p (decl)
tree decl;
{
return DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == MEM;
}

988
gnu/usr.bin/cc/cc1plus/gc.c Normal file
View File

@ -0,0 +1,988 @@
/* Garbage collection primitives for GNU C++.
Copyright (C) 1992, 1993 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include "tree.h"
#include "cp-tree.h"
#include "flags.h"
#undef NULL
#define NULL 0
extern tree define_function ();
extern tree build_t_desc_overload ();
/* This is the function decl for the (pseudo-builtin) __gc_protect
function. Args are (class *value, int index); Returns value. */
tree gc_protect_fndecl;
/* This is the function decl for the (pseudo-builtin) __gc_unprotect
function. Args are (int index); void return. */
tree gc_unprotect_fndecl;
/* This is the function decl for the (pseudo-builtin) __gc_push
function. Args are (int length); void return. */
tree gc_push_fndecl;
/* This is the function decl for the (pseudo-builtin) __gc_pop
function. Args are void; void return. */
tree gc_pop_fndecl;
/* Special integers that are used to represent bits in gc-safe objects. */
tree gc_nonobject;
tree gc_visible;
tree gc_white;
tree gc_offwhite;
tree gc_grey;
tree gc_black;
/* in c-common.c */
extern tree combine_strings PROTO((tree));
/* Predicate that returns non-zero if TYPE needs some kind of
entry for the GC. Returns zero otherwise. */
int
type_needs_gc_entry (type)
tree type;
{
tree ttype = type;
if (! flag_gc || type == error_mark_node)
return 0;
/* Aggregate types need gc entries if any of their members
need gc entries. */
if (IS_AGGR_TYPE (type))
{
tree binfos;
tree fields = TYPE_FIELDS (type);
int i;
/* We don't care about certain pointers. Pointers
to virtual baseclasses are always up front. We also
cull out virtual function table pointers because it's
easy, and it simplifies the logic.*/
while (fields
&& (DECL_NAME (fields) == NULL_TREE
|| VFIELD_NAME_P (DECL_NAME (fields))
|| VBASE_NAME_P (DECL_NAME (fields))
|| !strcmp (IDENTIFIER_POINTER (DECL_NAME (fields)), "__bits")))
fields = TREE_CHAIN (fields);
while (fields)
{
if (type_needs_gc_entry (TREE_TYPE (fields)))
return 1;
fields = TREE_CHAIN (fields);
}
binfos = TYPE_BINFO_BASETYPES (type);
if (binfos)
for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--)
if (type_needs_gc_entry (BINFO_TYPE (TREE_VEC_ELT (binfos, i))))
return 1;
return 0;
}
while (TREE_CODE (ttype) == ARRAY_TYPE
&& TREE_CODE (TREE_TYPE (ttype)) == ARRAY_TYPE)
ttype = TREE_TYPE (ttype);
if ((TREE_CODE (ttype) == POINTER_TYPE
|| TREE_CODE (ttype) == ARRAY_TYPE
|| TREE_CODE (ttype) == REFERENCE_TYPE)
&& IS_AGGR_TYPE (TREE_TYPE (ttype))
&& CLASSTYPE_DOSSIER (TREE_TYPE (ttype)))
return 1;
return 0;
}
/* Predicate that returns non-zero iff FROM is safe from the GC.
If TO is nonzero, it means we know that FROM is being stored
in TO, which make make it safe. */
int
value_safe_from_gc (to, from)
tree to, from;
{
/* First, return non-zero for easy cases: parameters,
static variables. */
if (TREE_CODE (from) == PARM_DECL
|| (TREE_CODE (from) == VAR_DECL
&& TREE_STATIC (from)))
return 1;
/* If something has its address taken, it cannot be
in the heap, so it doesn't need to be protected. */
if (TREE_CODE (from) == ADDR_EXPR || TREE_REFERENCE_EXPR (from))
return 1;
/* If we are storing into a static variable, then what
we store will be safe from the gc. */
if (to && TREE_CODE (to) == VAR_DECL
&& TREE_STATIC (to))
return 1;
/* Now recurse on structure of FROM. */
switch (TREE_CODE (from))
{
case COMPONENT_REF:
/* These guys are special, and safe. */
if (TREE_CODE (TREE_OPERAND (from, 1)) == FIELD_DECL
&& (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (from, 1)))
|| VBASE_NAME_P (DECL_NAME (TREE_OPERAND (from, 1)))))
return 1;
/* fall through... */
case NOP_EXPR:
case CONVERT_EXPR:
case NON_LVALUE_EXPR:
case WITH_CLEANUP_EXPR:
case SAVE_EXPR:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
if (value_safe_from_gc (to, TREE_OPERAND (from, 0)))
return 1;
break;
case VAR_DECL:
case PARM_DECL:
/* We can safely pass these things as parameters to functions. */
if (to == 0)
return 1;
case ARRAY_REF:
case INDIRECT_REF:
case RESULT_DECL:
case OFFSET_REF:
case CALL_EXPR:
case METHOD_CALL_EXPR:
break;
case COMPOUND_EXPR:
case TARGET_EXPR:
if (value_safe_from_gc (to, TREE_OPERAND (from, 1)))
return 1;
break;
case COND_EXPR:
if (value_safe_from_gc (to, TREE_OPERAND (from, 1))
&& value_safe_from_gc (to, TREE_OPERAND (from, 2)))
return 1;
break;
case PLUS_EXPR:
case MINUS_EXPR:
if ((type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 0)))
|| value_safe_from_gc (to, TREE_OPERAND (from, 0)))
&& (type_needs_gc_entry (TREE_TYPE (TREE_OPERAND (from, 1))) == 0
|| value_safe_from_gc (to, TREE_OPERAND (from, 1))))
return 1;
break;
case RTL_EXPR:
/* Every time we build an RTL_EXPR in the front-end, we must
ensure that everything in it is safe from the garbage collector.
??? This has only been done for `build_new'. */
return 1;
default:
my_friendly_abort (41);
}
if (to == 0)
return 0;
/* FROM wasn't safe. But other properties of TO might make it safe. */
switch (TREE_CODE (to))
{
case VAR_DECL:
case PARM_DECL:
/* We already culled out static VAR_DECLs above. */
return 0;
case COMPONENT_REF:
/* These guys are special, and safe. */
if (TREE_CODE (TREE_OPERAND (to, 1)) == FIELD_DECL
&& (VFIELD_NAME_P (DECL_NAME (TREE_OPERAND (to, 1)))
|| VBASE_NAME_P (DECL_NAME (TREE_OPERAND (to, 1)))))
return 1;
/* fall through... */
case NOP_EXPR:
case NON_LVALUE_EXPR:
case WITH_CLEANUP_EXPR:
case SAVE_EXPR:
case PREDECREMENT_EXPR:
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
return value_safe_from_gc (TREE_OPERAND (to, 0), from);
case COMPOUND_EXPR:
case TARGET_EXPR:
return value_safe_from_gc (TREE_OPERAND (to, 1), from);
case COND_EXPR:
return (value_safe_from_gc (TREE_OPERAND (to, 1), from)
&& value_safe_from_gc (TREE_OPERAND (to, 2), from));
case INDIRECT_REF:
case ARRAY_REF:
/* This used to be 0, but our current restricted model
allows this to be 1. We'll never get arrays this way. */
return 1;
default:
my_friendly_abort (42);
}
/* Catch-all case is that TO/FROM is not safe. */
return 0;
}
/* Function to build a static GC entry for DECL. TYPE is DECL's type.
For objects of type `class *', this is just an entry in the
static vector __PTR_LIST__.
For objects of type `class[]', this requires building an entry
in the static vector __ARR_LIST__.
For aggregates, this records all fields of type `class *'
and `class[]' in the respective lists above. */
void
build_static_gc_entry (decl, type)
tree decl;
tree type;
{
/* Now, figure out what sort of entry to build. */
if (TREE_CODE (type) == POINTER_TYPE
|| TREE_CODE (type) == REFERENCE_TYPE)
assemble_gc_entry (IDENTIFIER_POINTER (DECL_NAME (decl)));
else if (TREE_CODE (type) == RECORD_TYPE)
{
tree ref = get_temp_name (build_reference_type (type), 1);
DECL_INITIAL (ref) = build1 (ADDR_EXPR, TREE_TYPE (ref), decl);
TREE_CONSTANT (DECL_INITIAL (ref)) = 1;
finish_decl (ref, DECL_INITIAL (ref), 0, 0);
}
else
{
/* Not yet implemented.
Cons up a static variable that holds address and length info
and add that to ___ARR_LIST__. */
my_friendly_abort (43);
}
}
/* Protect FROM from the GC, assuming FROM is going to be
stored into TO. We handle three cases for TO here:
case 1: TO is a stack variable.
case 2: TO is zero (which means it is a parameter).
case 3: TO is a return value. */
tree
protect_value_from_gc (to, from)
tree to, from;
{
if (to == 0)
{
tree cleanup;
to = get_temp_regvar (TREE_TYPE (from), from);
/* Convert from integer to list form since we'll use it twice. */
DECL_GC_OFFSET (to) = build_tree_list (NULL_TREE, DECL_GC_OFFSET (to));
cleanup = build_function_call (gc_unprotect_fndecl,
DECL_GC_OFFSET (to));
if (! expand_decl_cleanup (to, cleanup))
{
compiler_error ("cannot unprotect parameter in this scope");
return error_mark_node;
}
}
/* Should never need to protect a value that's headed for static storage. */
if (TREE_STATIC (to))
my_friendly_abort (44);
switch (TREE_CODE (to))
{
case COMPONENT_REF:
case INDIRECT_REF:
return protect_value_from_gc (TREE_OPERAND (to, 0), from);
case VAR_DECL:
case PARM_DECL:
{
tree rval;
if (DECL_GC_OFFSET (to) == NULL_TREE)
{
/* Because of a cast or a conversion, we might stick
a value into a variable that would not normally
have a GC entry. */
DECL_GC_OFFSET (to) = size_int (++current_function_obstack_index);
}
if (TREE_CODE (DECL_GC_OFFSET (to)) != TREE_LIST)
{
DECL_GC_OFFSET (to)
= build_tree_list (NULL_TREE, DECL_GC_OFFSET (to));
}
current_function_obstack_usage = 1;
rval = build_function_call (gc_protect_fndecl,
tree_cons (NULL_TREE, from,
DECL_GC_OFFSET (to)));
TREE_TYPE (rval) = TREE_TYPE (from);
return rval;
}
}
/* If we fall through the switch, assume we lost. */
my_friendly_abort (45);
/* NOTREACHED */
return NULL_TREE;
}
/* Given the expression EXP of type `class *', return the head
of the object pointed to by EXP. */
tree
build_headof (exp)
tree exp;
{
tree type = TREE_TYPE (exp);
tree vptr, offset;
if (TREE_CODE (type) != POINTER_TYPE)
{
error ("`headof' applied to non-pointer type");
return error_mark_node;
}
if (flag_vtable_thunks)
abort();
vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp);
offset = build_component_ref (build_array_ref (vptr, integer_one_node),
get_identifier (VTABLE_DELTA_NAME),
NULL_TREE, 0);
return build (PLUS_EXPR, class_star_type_node, exp,
convert (integer_type_node, offset));
}
/* Given the expression EXP of type `class *', return the
type descriptor for the object pointed to by EXP. */
tree
build_classof (exp)
tree exp;
{
tree type = TREE_TYPE (exp);
tree vptr;
tree t_desc_entry;
if (TREE_CODE (type) != POINTER_TYPE)
{
error ("`classof' applied to non-pointer type");
return error_mark_node;
}
vptr = build1 (INDIRECT_REF, TYPE_POINTER_TO (vtable_entry_type), exp);
t_desc_entry = build_component_ref (build_array_ref (vptr, integer_one_node),
get_identifier (VTABLE_PFN_NAME),
NULL_TREE, 0);
TREE_TYPE (t_desc_entry) = TYPE_POINTER_TO (__t_desc_type_node);
return t_desc_entry;
}
/* Return the Type_info node associated with the expression EXP. If EXP is
a reference to a polymorphic class, return the dynamic type; otherwise
return the static type of the expression. */
tree
build_typeid (exp)
tree exp;
{
tree type;
if (exp == error_mark_node)
return error_mark_node;
type = TREE_TYPE (exp);
/* if b is an instance of B, typeid(b) == typeid(B). Do this before
reference trickiness. */
if (TREE_CODE (exp) == VAR_DECL && TREE_CODE (type) == RECORD_TYPE)
return get_typeid (type);
/* Apply trivial conversion T -> T& for dereferenced ptrs. */
if (TREE_CODE (type) == RECORD_TYPE)
type = build_reference_type (type);
/* If exp is a reference to polymorphic type, get the real Type_info. */
if (TREE_CODE (type) == REFERENCE_TYPE && TYPE_VIRTUAL_P (TREE_TYPE (type)))
{
/* build reference to Type_info from vtable. */
sorry ("finding Type_info for an object");
return error_mark_node;
}
/* otherwise return the Type_info for the static type of the expr. */
return get_typeid (type);
}
/* Return the Type_info object for TYPE, creating it if necessary. */
tree
get_typeid (type)
tree type;
{
if (type == error_mark_node)
return error_mark_node;
/* Is it useful (and/or correct) to have different typeids for `T &'
and `T'? */
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
/* build reference to static Type_info */
#if 1
sorry ("finding Type_info for a type");
return error_mark_node;
#else
register tree t = TYPE_TINFO (type);
if (t)
return t;
/* ... */
#endif
}
/* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working
paper. */
tree
build_dynamic_cast (type, expr)
tree type, expr;
{
enum tree_code tc = TREE_CODE (type);
tree exprtype = TREE_TYPE (expr);
enum tree_code ec = TREE_CODE (exprtype);
tree retval;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
switch (tc)
{
case POINTER_TYPE:
if (TREE_TYPE (type) == void_type_node)
break;
/* else fall through */
case REFERENCE_TYPE:
if (TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
&& TYPE_SIZE (TREE_TYPE (type)) != NULL_TREE)
break;
/* else fall through */
default:
cp_error ("`%#T' is not a valid type argument for dynamic_cast", type);
error ("(must be either pointer or reference to defined class or void *)");
return error_mark_node;
}
/* Apply trivial conversion T -> T& for dereferenced ptrs. */
if (ec == RECORD_TYPE)
{
exprtype = build_reference_type (exprtype);
ec = REFERENCE_TYPE;
}
/* the TREE_CODE of exprtype must match that of type. */
if (ec != tc)
{
cp_error ("`%E' (of type `%#T') fails to be of %s type", expr, exprtype,
tc == POINTER_TYPE ? "pointer" : "reference");
return error_mark_node;
}
/* If *type is an unambiguous accessible base class of *exprtype,
convert statically. */
{
int distance;
tree path;
distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1,
&path);
if (distance >= 0)
return build_vbase_path (PLUS_EXPR, type, expr, path, 0);
}
/* Otherwise *exprtype must be a polymorphic class (have a vtbl). */
if (TYPE_VIRTUAL_P (TREE_TYPE (exprtype)))
{
/* if TYPE is `void *', return pointer to complete object. */
if (tc == POINTER_TYPE && TREE_TYPE (type) == void_type_node)
{
/* if b is an object, dynamic_cast<void *>(&b) == (void *)&b. */
if (TREE_CODE (expr) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (expr, 0)) == VAR_DECL
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE)
return build1 (NOP_EXPR, type, expr);
sorry ("finding pointer to complete object");
return build1 (NOP_EXPR, type, expr);
}
else
{
tree retval;
/* If we got here, we can't convert statically. Therefore,
dynamic_cast<D&>(b) (b an object) cannot succeed. */
if (ec == REFERENCE_TYPE)
{
if (TREE_CODE (expr) == VAR_DECL
&& TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE)
{
cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed",
expr, type);
/* cplus_expand_throw (Bad_cast_node); */
sorry ("throwing Bad_cast");
return error_mark_node;
}
}
/* Ditto for dynamic_cast<D*>(&b). */
else if (TREE_CODE (expr) == ADDR_EXPR)
{
tree op = TREE_OPERAND (expr, 0);
if (TREE_CODE (op) == VAR_DECL
&& TREE_CODE (TREE_TYPE (op)) == RECORD_TYPE)
{
cp_warning ("dynamic_cast of `%E' to `%#T' can never succeed",
expr, type);
retval = build_int_2 (0, 0);
TREE_TYPE (retval) = type;
return retval;
}
}
/* Build run-time conversion. */
sorry ("run-time type conversion");
retval = build_int_2 (0, 0);
TREE_TYPE (retval) = type;
return retval;
}
}
cp_error ("cannot dynamic_cast `%E' (of type `%#T') to type `%#T'",
expr, exprtype, type);
return error_mark_node;
}
/* Build and initialize various sorts of descriptors. Every descriptor
node has a name associated with it (the name created by mangling).
For this reason, we use the identifier as our access to the __*_desc
nodes, instead of sticking them directly in the types. Otherwise we
would burden all built-in types (and pointer types) with slots that
we don't necessarily want to use.
For each descriptor we build, we build a variable that contains
the descriptor's information. When we need this info at runtime,
all we need is access to these variables.
Note: these constructors always return the address of the descriptor
info, since that is simplest for their mutual interaction. */
static tree
build_generic_desc (decl, elems)
tree decl;
tree elems;
{
tree init = build (CONSTRUCTOR, TREE_TYPE (decl), NULL_TREE, elems);
TREE_CONSTANT (init) = 1;
TREE_STATIC (init) = 1;
TREE_READONLY (init) = 1;
DECL_INITIAL (decl) = init;
TREE_STATIC (decl) = 1;
layout_decl (decl, 0);
finish_decl (decl, init, 0, 0);
return IDENTIFIER_AS_DESC (DECL_NAME (decl));
}
/* Build an initializer for a __t_desc node. So that we can take advantage
of recursion, we accept NULL for TYPE.
DEFINITION is greater than zero iff we must define the type descriptor
(as opposed to merely referencing it). 1 means treat according to
#pragma interface/#pragma implementation rules. 2 means define as
global and public, no matter what. */
tree
build_t_desc (type, definition)
tree type;
int definition;
{
tree tdecl;
tree tname, name_string;
tree elems, fields;
tree parents, vbases, offsets, ivars, methods, target_type;
int method_count = 0, field_count = 0;
if (type == NULL_TREE)
return NULL_TREE;
tname = build_t_desc_overload (type);
if (IDENTIFIER_AS_DESC (tname)
&& (!definition || TREE_ASM_WRITTEN (IDENTIFIER_AS_DESC (tname))))
return IDENTIFIER_AS_DESC (tname);
tdecl = lookup_name (tname, 0);
if (tdecl == NULL_TREE)
{
tdecl = build_decl (VAR_DECL, tname, __t_desc_type_node);
DECL_EXTERNAL (tdecl) = 1;
TREE_PUBLIC (tdecl) = 1;
tdecl = pushdecl_top_level (tdecl);
}
/* If we previously defined it, return the defined result. */
else if (definition && DECL_INITIAL (tdecl))
return IDENTIFIER_AS_DESC (tname);
if (definition)
{
tree taggr = type;
/* Let T* and T& be written only when T is written (if T is an aggr).
We do this for const, but not for volatile, since volatile
is rare and const is not. */
if (!TYPE_VOLATILE (taggr)
&& (TREE_CODE (taggr) == POINTER_TYPE
|| TREE_CODE (taggr) == REFERENCE_TYPE)
&& IS_AGGR_TYPE (TREE_TYPE (taggr)))
taggr = TREE_TYPE (taggr);
/* If we know that we don't need to write out this type's
vtable, then don't write out it's dossier. Somebody
else will take care of that. */
if (IS_AGGR_TYPE (taggr) && CLASSTYPE_VFIELD (taggr))
{
if (CLASSTYPE_VTABLE_NEEDS_WRITING (taggr))
{
TREE_PUBLIC (tdecl) = ! CLASSTYPE_INTERFACE_ONLY (taggr)
&& CLASSTYPE_INTERFACE_KNOWN (taggr);
TREE_STATIC (tdecl) = 1;
DECL_EXTERNAL (tdecl) = 0;
}
else
{
if (write_virtuals != 0)
TREE_PUBLIC (tdecl) = 1;
}
}
else
{
DECL_EXTERNAL (tdecl) = 0;
TREE_STATIC (tdecl) = 1;
TREE_PUBLIC (tdecl) = (definition > 1);
}
}
SET_IDENTIFIER_AS_DESC (tname, build_unary_op (ADDR_EXPR, tdecl, 0));
if (!definition || DECL_EXTERNAL (tdecl))
{
/* That's it! */
finish_decl (tdecl, 0, 0, 0);
return IDENTIFIER_AS_DESC (tname);
}
/* Show that we are defining the t_desc for this type. */
DECL_INITIAL (tdecl) = error_mark_node;
parents = build_tree_list (NULL_TREE, integer_zero_node);
vbases = build_tree_list (NULL_TREE, integer_zero_node);
offsets = build_tree_list (NULL_TREE, integer_zero_node);
methods = NULL_TREE;
ivars = NULL_TREE;
if (TYPE_LANG_SPECIFIC (type))
{
int i = CLASSTYPE_N_BASECLASSES (type);
tree method_vec = CLASSTYPE_METHOD_VEC (type);
tree *meth, *end;
tree binfos = TYPE_BINFO_BASETYPES (type);
tree vb = CLASSTYPE_VBASECLASSES (type);
while (--i >= 0)
parents = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (TREE_VEC_ELT (binfos, i)), 0), parents);
while (vb)
{
vbases = tree_cons (NULL_TREE, build_t_desc (BINFO_TYPE (vb), 0), vbases);
offsets = tree_cons (NULL_TREE, BINFO_OFFSET (vb), offsets);
vb = TREE_CHAIN (vb);
}
if (method_vec)
for (meth = TREE_VEC_END (method_vec),
end = &TREE_VEC_ELT (method_vec, 0); meth-- != end; )
if (*meth)
{
methods = tree_cons (NULL_TREE, build_m_desc (*meth), methods);
method_count++;
}
}
if (IS_AGGR_TYPE (type))
{
for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
if (TREE_CODE (fields) == FIELD_DECL
|| TREE_CODE (fields) == VAR_DECL)
{
ivars = tree_cons (NULL_TREE, build_i_desc (fields), ivars);
field_count++;
}
ivars = nreverse (ivars);
}
parents = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), parents, 0);
vbases = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node), vbases, 0);
offsets = finish_table (0, integer_type_node, offsets, 0);
if (methods == NULL_TREE)
methods = null_pointer_node;
else
methods = build_unary_op (ADDR_EXPR,
finish_table (0, __m_desc_type_node, methods, 0),
0);
if (ivars == NULL_TREE)
ivars = null_pointer_node;
else
ivars = build_unary_op (ADDR_EXPR,
finish_table (0, __i_desc_type_node, ivars, 0),
0);
if (TREE_TYPE (type))
target_type = build_t_desc (TREE_TYPE (type), definition);
else
target_type = integer_zero_node;
name_string = combine_strings (build_string (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname)));
elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0),
tree_cons (NULL_TREE,
TYPE_SIZE(type)? size_in_bytes(type) : integer_zero_node,
/* really should use bitfield initialization here. */
tree_cons (NULL_TREE, integer_zero_node,
tree_cons (NULL_TREE, target_type,
tree_cons (NULL_TREE, build_int_2 (field_count, 2),
tree_cons (NULL_TREE, build_int_2 (method_count, 2),
tree_cons (NULL_TREE, ivars,
tree_cons (NULL_TREE, methods,
tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, parents, 0),
tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, vbases, 0),
build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, offsets, 0))))))))))));
return build_generic_desc (tdecl, elems);
}
/* Build an initializer for a __i_desc node. */
tree
build_i_desc (decl)
tree decl;
{
tree elems, name_string;
tree taggr;
name_string = DECL_NAME (decl);
name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string)));
/* Now decide whether this ivar should cause it's type to get
def'd or ref'd in this file. If the type we are looking at
has a proxy definition, we look at the proxy (i.e., a
`foo *' is equivalent to a `foo'). */
taggr = TREE_TYPE (decl);
if ((TREE_CODE (taggr) == POINTER_TYPE
|| TREE_CODE (taggr) == REFERENCE_TYPE)
&& TYPE_VOLATILE (taggr) == 0)
taggr = TREE_TYPE (taggr);
elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0),
tree_cons (NULL_TREE, DECL_FIELD_BITPOS (decl),
build_tree_list (NULL_TREE, build_t_desc (TREE_TYPE (decl),
! IS_AGGR_TYPE (taggr)))));
taggr = build (CONSTRUCTOR, __i_desc_type_node, NULL_TREE, elems);
TREE_CONSTANT (taggr) = 1;
TREE_STATIC (taggr) = 1;
TREE_READONLY (taggr) = 1;
return taggr;
}
/* Build an initializer for a __m_desc node. */
tree
build_m_desc (decl)
tree decl;
{
tree taggr, elems, name_string;
tree parm_count, req_count, vindex, vcontext;
tree parms;
int p_count, r_count;
tree parm_types = NULL_TREE;
for (parms = TYPE_ARG_TYPES (TREE_TYPE (decl)), p_count = 0, r_count = 0;
parms != NULL_TREE; parms = TREE_CHAIN (parms), p_count++)
{
taggr = TREE_VALUE (parms);
if ((TREE_CODE (taggr) == POINTER_TYPE
|| TREE_CODE (taggr) == REFERENCE_TYPE)
&& TYPE_VOLATILE (taggr) == 0)
taggr = TREE_TYPE (taggr);
parm_types = tree_cons (NULL_TREE, build_t_desc (TREE_VALUE (parms),
! IS_AGGR_TYPE (taggr)),
parm_types);
if (TREE_PURPOSE (parms) == NULL_TREE)
r_count++;
}
parm_types = finish_table (0, TYPE_POINTER_TO (__t_desc_type_node),
nreverse (parm_types), 0);
parm_count = build_int_2 (p_count, 0);
req_count = build_int_2 (r_count, 0);
if (DECL_VINDEX (decl))
vindex = DECL_VINDEX (decl);
else
vindex = integer_zero_node;
if (DECL_CONTEXT (decl)
&& TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't')
vcontext = build_t_desc (DECL_CONTEXT (decl), 0);
else
vcontext = integer_zero_node;
name_string = DECL_NAME (decl);
if (name_string == NULL)
name_string = DECL_ASSEMBLER_NAME (decl);
name_string = combine_strings (build_string (IDENTIFIER_LENGTH (name_string)+1, IDENTIFIER_POINTER (name_string)));
/* Now decide whether the return type of this mvar
should cause it's type to get def'd or ref'd in this file.
If the type we are looking at has a proxy definition,
we look at the proxy (i.e., a `foo *' is equivalent to a `foo'). */
taggr = TREE_TYPE (TREE_TYPE (decl));
if ((TREE_CODE (taggr) == POINTER_TYPE
|| TREE_CODE (taggr) == REFERENCE_TYPE)
&& TYPE_VOLATILE (taggr) == 0)
taggr = TREE_TYPE (taggr);
elems = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, name_string, 0),
tree_cons (NULL_TREE, vindex,
tree_cons (NULL_TREE, vcontext,
tree_cons (NULL_TREE, build_t_desc (TREE_TYPE (TREE_TYPE (decl)),
! IS_AGGR_TYPE (taggr)),
tree_cons (NULL_TREE, build_c_cast (TYPE_POINTER_TO (default_function_type), build_unary_op (ADDR_EXPR, decl, 0)),
tree_cons (NULL_TREE, parm_count,
tree_cons (NULL_TREE, req_count,
build_tree_list (NULL_TREE, build_unary_op (ADDR_EXPR, parm_types, 0)))))))));
taggr = build (CONSTRUCTOR, __m_desc_type_node, NULL_TREE, elems);
TREE_CONSTANT (taggr) = 1;
TREE_STATIC (taggr) = 1;
TREE_READONLY (taggr) = 1;
return taggr;
}
/* Conditionally emit code to set up an unwind-protect for the
garbage collector. If this function doesn't do anything that involves
the garbage collector, then do nothing. Otherwise, call __gc_push
at the beginning and __gc_pop at the end.
NOTE! The __gc_pop function must operate transparently, since
it comes where the logical return label lies. This means that
at runtime *it* must preserve any return value registers. */
void
expand_gc_prologue_and_epilogue ()
{
extern tree maybe_gc_cleanup;
struct rtx_def *last_parm_insn, *mark;
extern struct rtx_def *get_last_insn ();
extern struct rtx_def *get_first_nonparm_insn ();
extern struct rtx_def *previous_insn ();
tree action;
/* If we didn't need the obstack, don't cons any space. */
if (current_function_obstack_index == 0
|| current_function_obstack_usage == 0)
return;
mark = get_last_insn ();
last_parm_insn = get_first_nonparm_insn ();
if (last_parm_insn == 0) last_parm_insn = mark;
else last_parm_insn = previous_insn (last_parm_insn);
action = build_function_call (gc_push_fndecl,
build_tree_list (NULL_TREE, size_int (++current_function_obstack_index)));
expand_expr_stmt (action);
reorder_insns (next_insn (mark), get_last_insn (), last_parm_insn);
/* This will be expanded as a cleanup. */
TREE_VALUE (maybe_gc_cleanup)
= build_function_call (gc_pop_fndecl, NULL_TREE);
}
/* Some day we'll use this function as a call-back and clean
up all the unnecessary gc dribble that we otherwise create. */
void
lang_expand_end_bindings (first, last)
struct rtx_def *first, *last;
{
}
void
init_gc_processing ()
{
tree parmtypes = hash_tree_chain (class_star_type_node,
hash_tree_chain (integer_type_node, NULL_TREE));
gc_protect_fndecl = define_function ("__gc_protect",
build_function_type (class_star_type_node, parmtypes),
NOT_BUILT_IN, 0, 0);
parmtypes = hash_tree_chain (integer_type_node, NULL_TREE);
gc_unprotect_fndecl = define_function ("__gc_unprotect",
build_function_type (void_type_node, parmtypes),
NOT_BUILT_IN, 0, 0);
gc_push_fndecl = define_function ("__gc_push",
TREE_TYPE (gc_unprotect_fndecl),
NOT_BUILT_IN, 0, 0);
gc_pop_fndecl = define_function ("__gc_pop",
build_function_type (void_type_node,
void_list_node),
NOT_BUILT_IN, 0, 0);
gc_nonobject = build_int_2 (0x80000000, 0);
gc_visible = build_int_2 (0x40000000, 0);
gc_white = integer_zero_node;
gc_offwhite = build_int_2 (0x10000000, 0);
gc_grey = build_int_2 (0x20000000, 0);
gc_black = build_int_2 (0x30000000, 0);
}

View File

@ -0,0 +1,197 @@
/* C code produced by gperf version 2.5 (GNU C++ version) */
/* Command-line: gperf -p -j1 -g -o -t -N is_reserved_word -k1,4,7,$ /deneb/blob/jason/g++/small/devo/gcc/cp/gxx.gperf */
/* Command-line: gperf -p -j1 -g -o -t -N is_reserved_word -k1,4,$,7 gplus.gperf */
struct resword { char *name; short token; enum rid rid;};
#define TOTAL_KEYWORDS 86
#define MIN_WORD_LENGTH 2
#define MAX_WORD_LENGTH 16
#define MIN_HASH_VALUE 4
#define MAX_HASH_VALUE 171
/* maximum key range = 168, duplicates = 0 */
#ifdef __GNUC__
inline
#endif
static unsigned int
hash (str, len)
register char *str;
register int unsigned len;
{
static unsigned char asso_values[] =
{
172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
172, 172, 172, 172, 172, 172, 172, 172, 172, 172,
172, 172, 172, 172, 172, 0, 172, 36, 1, 61,
0, 0, 30, 44, 44, 35, 172, 7, 12, 53,
40, 17, 6, 172, 28, 2, 4, 35, 31, 51,
5, 7, 172, 172, 172, 172, 172, 172,
};
register int hval = len;
switch (hval)
{
default:
case 7:
hval += asso_values[str[6]];
case 6:
case 5:
case 4:
hval += asso_values[str[3]];
case 3:
case 2:
case 1:
hval += asso_values[str[0]];
}
return hval + asso_values[str[len - 1]];
}
#ifdef __GNUC__
inline
#endif
struct resword *
is_reserved_word (str, len)
register char *str;
register unsigned int len;
{
static struct resword wordlist[] =
{
{"",}, {"",}, {"",}, {"",},
{"else", ELSE, NORID,},
{"",},
{"delete", DELETE, NORID,},
{"double", TYPESPEC, RID_DOUBLE,},
{"true", CXX_TRUE, NORID,},
{"__asm__", GCC_ASM_KEYWORD, NORID},
{"typeid", TYPEID, NORID,},
{"",},
{"this", THIS, NORID,},
{"",},
{"try", TRY, NORID,},
{"",}, {"",}, {"",}, {"",},
{"do", DO, NORID,},
{"",},
{"static_cast", STATIC_CAST, NORID,},
{"template", TEMPLATE, RID_TEMPLATE,},
{"protected", VISSPEC, RID_PROTECTED,},
{"",},
{"__classof__", CLASSOF, NORID},
{"",},
{"__headof__", HEADOF, NORID},
{"",},
{"bool", TYPESPEC, RID_BOOL,},
{"__const__", TYPE_QUAL, RID_CONST},
{"__volatile", TYPE_QUAL, RID_VOLATILE},
{"__const", TYPE_QUAL, RID_CONST},
{"__volatile__", TYPE_QUAL, RID_VOLATILE},
{"__typeof__", TYPEOF, NORID},
{"void", TYPESPEC, RID_VOID,},
{"friend", SCSPEC, RID_FRIEND,},
{"false", CXX_FALSE, NORID,},
{"sizeof", SIZEOF, NORID,},
{"short", TYPESPEC, RID_SHORT,},
{"typeof", TYPEOF, NORID,},
{"",},
{"int", TYPESPEC, RID_INT,},
{"__signed", TYPESPEC, RID_SIGNED},
{"private", VISSPEC, RID_PRIVATE,},
{"__signed__", TYPESPEC, RID_SIGNED},
{"extern", SCSPEC, RID_EXTERN,},
{"struct", AGGR, RID_RECORD,},
{"signed", TYPESPEC, RID_SIGNED,},
{"break", BREAK, NORID,},
{"__attribute", ATTRIBUTE, NORID},
{"default", DEFAULT, NORID,},
{"__attribute__", ATTRIBUTE, NORID},
{"__classof", CLASSOF, NORID},
{"sigof", SIGOF, NORID /* Extension */,},
{"__headof", HEADOF, NORID},
{"switch", SWITCH, NORID,},
{"__label__", LABEL, NORID},
{"__extension__", EXTENSION, NORID},
{"",},
{"__asm", GCC_ASM_KEYWORD, NORID},
{"for", FOR, NORID,},
{"__typeof", TYPEOF, NORID},
{"__alignof__", ALIGNOF, NORID},
{"",},
{"case", CASE, NORID,},
{"virtual", SCSPEC, RID_VIRTUAL,},
{"if", IF, NORID,},
{"while", WHILE, NORID,},
{"",},
{"class", AGGR, RID_CLASS,},
{"typedef", SCSPEC, RID_TYPEDEF,},
{"const", TYPE_QUAL, RID_CONST,},
{"static", SCSPEC, RID_STATIC,},
{"auto", SCSPEC, RID_AUTO,},
{"float", TYPESPEC, RID_FLOAT,},
{"inline", SCSPEC, RID_INLINE,},
{"throw", THROW, NORID,},
{"unsigned", TYPESPEC, RID_UNSIGNED,},
{"",},
{"headof", HEADOF, NORID,},
{"",},
{"goto", GOTO, NORID,},
{"",}, {"",},
{"public", VISSPEC, RID_PUBLIC,},
{"signature", AGGR, RID_SIGNATURE /* Extension */,},
{"volatile", TYPE_QUAL, RID_VOLATILE,},
{"__inline", SCSPEC, RID_INLINE},
{"overload", OVERLOAD, NORID,},
{"__inline__", SCSPEC, RID_INLINE},
{"__alignof", ALIGNOF, NORID},
{"asm", ASM_KEYWORD, NORID,},
{"",},
{"new", NEW, NORID,},
{"",},
{"mutable", SCSPEC, RID_MUTABLE,},
{"union", AGGR, RID_UNION,},
{"operator", OPERATOR, NORID,},
{"register", SCSPEC, RID_REGISTER,},
{"",}, {"",},
{"__wchar_t", TYPESPEC, RID_WCHAR /* Unique to ANSI C++ */,},
{"",},
{"long", TYPESPEC, RID_LONG,},
{"",}, {"",}, {"",},
{"continue", CONTINUE, NORID,},
{"return", RETURN, NORID,},
{"enum", ENUM, NORID,},
{"",}, {"",},
{"dynamic_cast", DYNAMIC_CAST, NORID,},
{"",}, {"",},
{"reinterpret_cast", REINTERPRET_CAST, NORID,},
{"",}, {"",}, {"",}, {"",},
{"char", TYPESPEC, RID_CHAR,},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"classof", CLASSOF, NORID,},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"const_cast", CONST_CAST, NORID,},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
{"",}, {"",}, {"",}, {"",}, {"",},
{"catch", CATCH, NORID,},
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
register int key = hash (str, len);
if (key <= MAX_HASH_VALUE && key >= 0)
{
register char *s = wordlist[key].name;
if (*s == *str && !strcmp (str + 1, s + 1))
return &wordlist[key];
}
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,184 @@
/* Input handling for G++.
Copyright (C) 1992, 1993 Free Software Foundation, Inc.
Written by Ken Raeburn (raeburn@cygnus.com) while at Watchmaker Computing.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* G++ needs to do enough saving and re-parsing of text that it is
necessary to abandon the simple FILE* model and use a mechanism where
we can pre-empt one input stream with another derived from saved text;
we may need to do this arbitrarily often, and cannot depend on having
the GNU library available, so FILE objects just don't cut it.
This file is written as a separate module, but can be included by
lex.c for very minor efficiency gains (primarily in function
inlining). */
#include <stdio.h>
#include "obstack.h"
extern FILE *finput;
struct pending_input *save_pending_input ();
void restore_pending_input ();
struct input_source {
/* saved string */
char *str;
int length;
/* current position, when reading as input */
int offset;
/* obstack to free this input string from when finished, if any */
struct obstack *obstack;
/* linked list maintenance */
struct input_source *next;
/* values to restore after reading all of current string */
char *filename;
int lineno;
struct pending_input *input;
int putback_char;
};
static struct input_source *input, *free_inputs;
extern char *input_filename;
extern int lineno;
#ifdef __GNUC__
#define inline __inline__
#else
#define inline
#endif
static inline struct input_source *
allocate_input ()
{
struct input_source *inp;
if (free_inputs)
{
inp = free_inputs;
free_inputs = inp->next;
inp->next = 0;
return inp;
}
inp = (struct input_source *) xmalloc (sizeof (struct input_source));
inp->next = 0;
inp->obstack = 0;
return inp;
}
static inline void
free_input (inp)
struct input_source *inp;
{
if (inp->obstack)
obstack_free (inp->obstack, inp->str);
inp->obstack = 0;
inp->str = 0;
inp->length = 0;
inp->next = free_inputs;
free_inputs = inp;
}
static int putback_char = -1;
/* Some of these external functions are declared inline in case this file
is included in lex.c. */
inline
void
feed_input (str, len, delete)
char *str;
int len;
struct obstack *delete;
{
struct input_source *inp = allocate_input ();
/* This shouldn't be necessary. */
while (len && !str[len-1])
len--;
inp->str = str;
inp->length = len;
inp->obstack = delete;
inp->offset = 0;
inp->next = input;
inp->filename = input_filename;
inp->lineno = lineno;
inp->input = save_pending_input ();
inp->putback_char = putback_char;
putback_char = -1;
input = inp;
}
struct pending_input *to_be_restored; /* XXX */
extern int end_of_file;
int
getch ()
{
if (putback_char != -1)
{
int ch = putback_char;
putback_char = -1;
return ch;
}
if (input)
{
if (input->offset == input->length)
{
struct input_source *inp = input;
my_friendly_assert (putback_char == -1, 223);
to_be_restored = inp->input;
input->offset++;
return EOF;
}
else if (input->offset > input->length)
{
struct input_source *inp = input;
end_of_file = 0;
input = inp->next;
input_filename = inp->filename;
lineno = inp->lineno;
/* Get interface/implementation back in sync. */
extract_interface_info ();
putback_char = inp->putback_char;
free_input (inp);
return getch ();
}
if (input)
return input->str[input->offset++];
}
return getc (finput);
}
inline
void
put_back (ch)
int ch;
{
my_friendly_assert (putback_char == -1, 224);
putback_char = ch;
}
inline
int
input_redirected ()
{
return input != 0;
}

4818
gnu/usr.bin/cc/cc1plus/lex.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,130 @@
/* Define constants and variables for communication with parse.y.
Copyright (C) 1987, 1992, 1993 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
and by Brendan Kehoe (brendan@cygnus.com).
This file is part of GNU CC.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY. No author or distributor
accepts responsibility to anyone for the consequences of using it
or for whether it serves any particular purpose or works at all,
unless he says so in writing. Refer to the GNU CC General Public
License for full details.
Everyone is granted permission to copy, modify and redistribute
GNU CC, but only under the conditions described in the
GNU CC General Public License. A copy of this license is
supposed to have been given to you along with GNU CC so you
can know your rights and responsibilities. It should be in a
file named COPYING. Among other things, the copyright notice
and this notice must be preserved on all copies. */
enum rid
{
RID_UNUSED,
RID_INT,
RID_BOOL,
RID_CHAR,
RID_WCHAR,
RID_FLOAT,
RID_DOUBLE,
RID_VOID,
/* C++ extension */
RID_CLASS,
RID_RECORD,
RID_UNION,
RID_ENUM,
RID_LONGLONG,
/* This is where grokdeclarator starts its search when setting the specbits.
The first seven are in the order of most frequently used, as found
building libg++. */
RID_EXTERN,
RID_CONST,
RID_LONG,
RID_TYPEDEF,
RID_UNSIGNED,
RID_SHORT,
RID_INLINE,
RID_STATIC,
RID_REGISTER,
RID_VOLATILE,
RID_FRIEND,
RID_VIRTUAL,
RID_PUBLIC,
RID_PRIVATE,
RID_PROTECTED,
RID_SIGNED,
RID_EXCEPTION,
RID_RAISES,
RID_AUTO,
RID_MUTABLE,
RID_TEMPLATE,
RID_SIGNATURE,
/* Before adding enough to get up to 64, the RIDBIT_* macros
will have to be changed a little. */
RID_MAX
};
#define NORID RID_UNUSED
#define RID_FIRST_MODIFIER RID_EXTERN
/* The type that can represent all values of RIDBIT. */
/* We assume that we can stick in at least 32 bits into this. */
typedef struct { unsigned long idata[2]; }
RID_BIT_TYPE;
/* Be careful, all these modify N twice. */
#define RIDBIT_SETP(N, V) (((unsigned long)1 << (int) ((N)%32)) \
& (V).idata[(N)/32])
#define RIDBIT_NOTSETP(NN, VV) (! RIDBIT_SETP (NN, VV))
#define RIDBIT_SET(N, V) do { \
(V).idata[(N)/32] \
|= ((unsigned long)1 << (int) ((N)%32)); \
} while (0)
#define RIDBIT_RESET(N, V) do { \
(V).idata[(N)/32] \
&= ~((unsigned long)1 << (int) ((N)%32)); \
} while (0)
#define RIDBIT_RESET_ALL(V) do { \
(V).idata[0] = 0; \
(V).idata[1] = 0; \
} while (0)
#define RIDBIT_ANY_SET(V) ((V).idata[0] || (V).idata[1])
/* The elements of `ridpointers' are identifier nodes
for the reserved type names and storage classes.
It is indexed by a RID_... value. */
extern tree ridpointers[(int) RID_MAX];
/* the declaration found for the last IDENTIFIER token read in.
yylex must look this up to detect typedefs, which get token type TYPENAME,
so it is left around in case the identifier is not a typedef but is
used in a context which makes it a reference to a variable. */
extern tree lastiddecl;
extern char *token_buffer; /* Pointer to token buffer. */
/* Back-door communication channel to the lexer. */
extern int looking_for_typename;
extern int looking_for_template;
/* Tell the lexer where to look for names. */
extern tree got_scope;
/* Pending language change.
Positive is push count, negative is pop count. */
extern int pending_lang_change;
extern tree make_pointer_declarator (), make_reference_declarator ();
extern void reinit_parse_for_function ();
extern void reinit_parse_for_method ();
extern int yylex ();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,84 @@
typedef union {long itype; tree ttype; char *strtype; enum tree_code code; } YYSTYPE;
#define IDENTIFIER 258
#define TYPENAME 259
#define SCSPEC 260
#define TYPESPEC 261
#define TYPE_QUAL 262
#define CONSTANT 263
#define STRING 264
#define ELLIPSIS 265
#define SIZEOF 266
#define ENUM 267
#define IF 268
#define ELSE 269
#define WHILE 270
#define DO 271
#define FOR 272
#define SWITCH 273
#define CASE 274
#define DEFAULT 275
#define BREAK 276
#define CONTINUE 277
#define RETURN 278
#define GOTO 279
#define ASM_KEYWORD 280
#define GCC_ASM_KEYWORD 281
#define TYPEOF 282
#define ALIGNOF 283
#define HEADOF 284
#define CLASSOF 285
#define SIGOF 286
#define ATTRIBUTE 287
#define EXTENSION 288
#define LABEL 289
#define AGGR 290
#define VISSPEC 291
#define DELETE 292
#define NEW 293
#define OVERLOAD 294
#define THIS 295
#define OPERATOR 296
#define CXX_TRUE 297
#define CXX_FALSE 298
#define LEFT_RIGHT 299
#define TEMPLATE 300
#define TYPEID 301
#define DYNAMIC_CAST 302
#define STATIC_CAST 303
#define REINTERPRET_CAST 304
#define CONST_CAST 305
#define SCOPE 306
#define EMPTY 307
#define PTYPENAME 308
#define ASSIGN 309
#define OROR 310
#define ANDAND 311
#define MIN_MAX 312
#define EQCOMPARE 313
#define ARITHCOMPARE 314
#define LSHIFT 315
#define RSHIFT 316
#define POINTSAT_STAR 317
#define DOT_STAR 318
#define UNARY 319
#define PLUSPLUS 320
#define MINUSMINUS 321
#define HYPERUNARY 322
#define PAREN_STAR_PAREN 323
#define POINTSAT 324
#define TRY 325
#define CATCH 326
#define THROW 327
#define TYPENAME_ELLIPSIS 328
#define PRE_PARSED_FUNCTION_DECL 329
#define EXTERN_LANG_STRING 330
#define ALL 331
#define PRE_PARSED_CLASS_DECL 332
#define TYPENAME_DEFN 333
#define IDENTIFIER_DEFN 334
#define PTYPENAME_DEFN 335
#define END_OF_SAVED_INPUT 336
extern YYSTYPE yylval;
#define YYEMPTY -2

2465
gnu/usr.bin/cc/cc1plus/pt.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,167 @@
/* Prints out trees in human readable form.
Copyright (C) 1992, 1993 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include "tree.h"
#include <stdio.h>
#include "cp-tree.h"
void
print_lang_decl (file, node, indent)
FILE *file;
tree node;
int indent;
{
if (!DECL_LANG_SPECIFIC (node))
return;
/* A FIELD_DECL only has the flags structure, which we aren't displaying
anyways. */
if (DECL_MUTABLE_P (node))
{
indent_to (file, indent + 3);
fprintf (file, " mutable ");
}
if (TREE_CODE (node) == FIELD_DECL)
return;
indent_to (file, indent + 3);
if (DECL_MAIN_VARIANT (node))
{
fprintf (file, " decl-main-variant ");
fprintf (file, HOST_PTR_PRINTF, DECL_MAIN_VARIANT (node));
}
if (DECL_PENDING_INLINE_INFO (node))
{
fprintf (file, " pending-inline-info ");
fprintf (file, HOST_PTR_PRINTF, DECL_PENDING_INLINE_INFO (node));
}
if (DECL_TEMPLATE_INFO (node))
{
fprintf (file, " template-info ");
fprintf (file, HOST_PTR_PRINTF, DECL_TEMPLATE_INFO (node));
}
}
void
print_lang_type (file, node, indent)
FILE *file;
register tree node;
int indent;
{
if (TREE_CODE (node) == TEMPLATE_TYPE_PARM)
{
print_node (file, "tinfo", TYPE_VALUES (node), indent + 4);
return;
}
if (TREE_CODE (node) == UNINSTANTIATED_P_TYPE)
{
print_node (file, "template", UPT_TEMPLATE (node), indent + 4);
print_node (file, "parameters", UPT_PARMS (node), indent + 4);
return;
}
if (! (TREE_CODE (node) == RECORD_TYPE
|| TREE_CODE (node) == UNION_TYPE))
return;
if (!TYPE_LANG_SPECIFIC (node))
return;
indent_to (file, indent + 3);
if (TYPE_NEEDS_CONSTRUCTING (node))
fputs ( "needs-constructor", file);
if (TYPE_NEEDS_DESTRUCTOR (node))
fputs (" needs-destructor", file);
if (TYPE_HAS_DESTRUCTOR (node))
fputs (" ~X()", file);
if (TYPE_HAS_DEFAULT_CONSTRUCTOR (node))
fputs (" X()", file);
if (TYPE_HAS_CONVERSION (node))
fputs (" has-type-conversion", file);
if (TYPE_HAS_INT_CONVERSION (node))
fputs (" has-int-conversion", file);
if (TYPE_HAS_REAL_CONVERSION (node))
fputs (" has-float-conversion", file);
if (TYPE_HAS_INIT_REF (node))
{
if (TYPE_HAS_CONST_INIT_REF (node))
fputs (" X(constX&)", file);
else
fputs (" X(X&)", file);
}
if (TYPE_GETS_NEW (node) & 1)
fputs (" new", file);
if (TYPE_GETS_NEW (node) & 2)
fputs (" new[]", file);
if (TYPE_GETS_DELETE (node) & 1)
fputs (" delete", file);
if (TYPE_GETS_DELETE (node) & 2)
fputs (" delete[]", file);
if (TYPE_HAS_ASSIGNMENT (node))
fputs (" has=", file);
if (TYPE_HAS_ASSIGN_REF (node))
fputs (" this=(X&)", file);
if (TYPE_OVERLOADS_METHOD_CALL_EXPR (node))
fputs (" op->()", file);
if (TYPE_GETS_INIT_AGGR (node))
fputs (" gets X(X, ...)", file);
if (TYPE_OVERLOADS_CALL_EXPR (node))
fputs (" op()", file);
if (TYPE_OVERLOADS_ARRAY_REF (node))
fputs (" op[]", file);
if (TYPE_OVERLOADS_ARROW (node))
fputs (" op->", file);
if (TYPE_USES_MULTIPLE_INHERITANCE (node))
fputs (" uses-multiple-inheritance", file);
if (TREE_CODE (node) == RECORD_TYPE)
{
fprintf (file, " n_parents %d n_ancestors %d",
CLASSTYPE_N_BASECLASSES (node),
CLASSTYPE_N_SUPERCLASSES (node));
fprintf (file, " use_template=%d", CLASSTYPE_USE_TEMPLATE (node));
if (CLASSTYPE_INTERFACE_ONLY (node))
fprintf (file, " interface-only");
if (CLASSTYPE_INTERFACE_UNKNOWN (node))
fprintf (file, " interface-unknown");
print_node (file, "member-functions", CLASSTYPE_METHOD_VEC (node),
indent + 4);
print_node (file, "baselinks",
TYPE_BINFO_BASETYPES (node) ? CLASSTYPE_BASELINK_VEC (node) : NULL_TREE,
indent + 4);
}
}
void
print_lang_identifier (file, node, indent)
FILE *file;
tree node;
int indent;
{
print_node (file, "global", IDENTIFIER_GLOBAL_VALUE (node), indent + 4);
print_node (file, "class", IDENTIFIER_CLASS_VALUE (node), indent + 4);
print_node (file, "local", IDENTIFIER_LOCAL_VALUE (node), indent + 4);
print_node (file, "label", IDENTIFIER_LABEL_VALUE (node), indent + 4);
print_node (file, "template", IDENTIFIER_TEMPLATE (node), indent + 4);
print_node (file, "implicit", IDENTIFIER_IMPLICIT_DECL (node), indent + 4);
print_node (file, "error locus", IDENTIFIER_ERROR_LOCUS (node), indent + 4);
}

File diff suppressed because it is too large Load Diff

1023
gnu/usr.bin/cc/cc1plus/sig.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,436 @@
/* Type Analyzer for GNU C++.
Copyright (C) 1987, 1989, 1992, 1993 Free Software Foundation, Inc.
Hacked... nay, bludgeoned... by Mark Eichin (eichin@cygnus.com)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This file is the type analyzer for GNU C++. To debug it, define SPEW_DEBUG
when compiling parse.c and spew.c. */
#include "config.h"
#include <stdio.h>
#include "input.h"
#include "tree.h"
#include "lex.h"
#include "parse.h"
#include "cp-tree.h"
#include "flags.h"
#include "obstack.h"
/* This takes a token stream that hasn't decided much about types and
tries to figure out as much as it can, with excessive lookahead and
backtracking. */
/* fifo of tokens recognized and available to parser. */
struct token {
/* The values for YYCHAR will fit in a short. */
short yychar;
short end_of_file;
YYSTYPE yylval;
};
static int do_aggr ();
/* From lex.c: */
/* the declaration found for the last IDENTIFIER token read in.
yylex must look this up to detect typedefs, which get token type TYPENAME,
so it is left around in case the identifier is not a typedef but is
used in a context which makes it a reference to a variable. */
extern tree lastiddecl; /* let our brains leak out here too */
extern int yychar; /* the lookahead symbol */
extern YYSTYPE yylval; /* the semantic value of the */
/* lookahead symbol */
extern int end_of_file;
struct obstack token_obstack;
int first_token;
#ifdef SPEW_DEBUG
int spew_debug = 0;
static unsigned int yylex_ctr = 0;
static int debug_yychar ();
#endif
/* Initialize token_obstack. Called once, from init_lex. */
void
init_spew ()
{
gcc_obstack_init(&token_obstack);
}
#ifdef SPEW_DEBUG
/* Use functions for debugging... */
/* Return the number of tokens available on the fifo. */
static int
num_tokens ()
{
return (obstack_object_size(&token_obstack)/sizeof(struct token))
- first_token;
}
/* Fetch the token N down the line from the head of the fifo. */
static struct token*
nth_token (n)
int n;
{
/* could just have this do slurp_ implicitly, but this way is easier
* to debug... */
my_friendly_assert (n < num_tokens(), 298);
return ((struct token*)obstack_base(&token_obstack))+n+first_token;
}
/* Add a token to the token fifo. */
static void
add_token (t)
struct token* t;
{
obstack_grow(&token_obstack,t,sizeof (struct token));
}
/* Consume the next token out of the fifo. */
static void
consume_token()
{
if (num_tokens() == 1)
{
obstack_free(&token_obstack, obstack_base (&token_obstack));
first_token = 0;
}
else
first_token++;
}
#else
/* ...otherwise use macros. */
#define num_tokens() \
((obstack_object_size(&token_obstack)/sizeof(struct token)) - first_token)
#define nth_token(N) \
(((struct token*)obstack_base(&token_obstack))+(N)+first_token)
#define add_token(T) obstack_grow(&token_obstack, (T), sizeof (struct token))
#define consume_token() \
(num_tokens() == 1 \
? (obstack_free (&token_obstack, obstack_base (&token_obstack)), \
(first_token = 0)) \
: first_token++)
#endif
/* Pull in enough tokens from real_yylex that the queue is N long beyond
the current token. */
static void
scan_tokens (n)
int n;
{
int i;
struct token *tmp;
/* We cannot read past certain tokens, so make sure we don't. */
i = num_tokens ();
if (i > n)
return;
while (i-- > 0)
{
tmp = nth_token (i);
/* Never read past these characters: they might separate
the current input stream from one we save away later. */
if (tmp->yychar == '{' || tmp->yychar == ':' || tmp->yychar == ';')
goto pad_tokens;
}
while (num_tokens() <= n)
{
obstack_blank(&token_obstack,sizeof (struct token));
tmp = ((struct token *)obstack_next_free (&token_obstack))-1;
tmp->yychar = real_yylex();
tmp->end_of_file = end_of_file;
tmp->yylval = yylval;
end_of_file = 0;
if (tmp->yychar == '{'
|| tmp->yychar == ':'
|| tmp->yychar == ';')
{
pad_tokens:
while (num_tokens () <= n)
{
obstack_blank(&token_obstack,sizeof (struct token));
tmp = ((struct token *)obstack_next_free (&token_obstack))-1;
tmp->yychar = EMPTY;
tmp->end_of_file = 0;
}
}
}
}
/* Create room for N tokens at the front of the fifo. This is used
to insert new tokens into the stream ahead of the current token. */
static void
shift_tokens (n)
int n;
{
if (first_token >= n)
first_token -= n;
else
{
int old_token_count = num_tokens ();
char *tmp;
obstack_blank (&token_obstack, (n-first_token) * sizeof (struct token));
if (old_token_count)
{
tmp = (char *)alloca ((num_tokens () + (n-first_token))
* sizeof (struct token));
/* This move does not rely on the system being able to handle
overlapping moves. */
bcopy (nth_token (0), tmp, old_token_count * sizeof (struct token));
bcopy (tmp, nth_token (n), old_token_count * sizeof (struct token));
}
first_token = 0;
}
}
static int
probe_obstack (h, obj, nlevels)
struct obstack *h;
tree obj;
unsigned int nlevels;
{
register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
register struct _obstack_chunk* plp; /* point to previous chunk if any */
lp = (h)->chunk;
/* We use >= rather than > since the object cannot be exactly at
the beginning of the chunk but might be an empty object exactly
at the end of an adjacent chunk. */
for (; nlevels != 0 && lp != 0 && ((tree)lp >= obj || (tree)lp->limit < obj);
nlevels -= 1)
{
plp = lp->prev;
lp = plp;
}
return nlevels != 0 && lp != 0;
}
/* from lex.c: */
/* Value is 1 (or 2) if we should try to make the next identifier look like
a typename (when it may be a local variable or a class variable).
Value is 0 if we treat this name in a default fashion. */
extern int looking_for_typename;
int looking_for_template;
extern struct obstack *current_obstack, *saveable_obstack;
tree got_scope;
int
yylex()
{
struct token tmp_token;
tree trrr;
retry:
#ifdef SPEW_DEBUG
if (spew_debug)
{
yylex_ctr ++;
fprintf(stderr, "\t\t## %d ##",yylex_ctr);
}
#endif
/* if we've got tokens, send them */
if (num_tokens())
{
tmp_token= *nth_token(0);
/* TMP_TOKEN.YYLVAL.TTYPE may have been allocated on the wrong obstack.
If we don't find it in CURRENT_OBSTACK's current or immediately
previous chunk, assume it was and copy it to the current obstack. */
if ((tmp_token.yychar == CONSTANT
|| tmp_token.yychar == STRING)
&& ! TREE_PERMANENT (tmp_token.yylval.ttype)
&& ! probe_obstack (current_obstack, tmp_token.yylval.ttype, 2)
&& ! probe_obstack (saveable_obstack, tmp_token.yylval.ttype, 2))
tmp_token.yylval.ttype = copy_node (tmp_token.yylval.ttype);
}
else
{
/* if not, grab the next one and think about it */
tmp_token.yychar = real_yylex ();
tmp_token.yylval = yylval;
tmp_token.end_of_file = end_of_file;
add_token(&tmp_token);
}
/* many tokens just need to be returned. At first glance, all we
* have to do is send them back up, but some of them are needed to
* figure out local context. */
switch(tmp_token.yychar)
{
case EMPTY:
/* This is a lexical no-op. */
consume_token ();
#ifdef SPEW_DEBUG
if (spew_debug)
debug_yychar (tmp_token.yychar);
#endif
goto retry;
case IDENTIFIER:
scan_tokens (1);
if (nth_token (1)->yychar == SCOPE)
/* Don't interfere with the setting from an 'aggr' prefix. */
looking_for_typename++;
else if (nth_token (1)->yychar == '<')
looking_for_template = 1;
trrr = lookup_name (tmp_token.yylval.ttype, -2);
if (trrr)
{
tmp_token.yychar = identifier_type (trrr);
switch (tmp_token.yychar)
{
case TYPENAME:
lastiddecl = identifier_typedecl_value (tmp_token.yylval.ttype);
if (lastiddecl != trrr)
{
lastiddecl = trrr;
if (got_scope)
tmp_token.yylval.ttype = DECL_NESTED_TYPENAME (trrr);
}
break;
case IDENTIFIER:
lastiddecl = trrr;
break;
case PTYPENAME:
lastiddecl = NULL_TREE;
break;
default:
my_friendly_abort (101);
}
}
else
lastiddecl = trrr;
got_scope = NULL_TREE;
/* and fall through to... */
case TYPENAME:
case PTYPENAME:
consume_token ();
if (looking_for_typename > 0)
looking_for_typename--;
looking_for_template = 0;
break;
case SCSPEC:
/* do_aggr needs to check if the previous token was RID_FRIEND,
so just increment first_token instead of calling consume_token. */
first_token++;
break;
case TYPESPEC:
consume_token ();
break;
case AGGR:
*nth_token(0) = tmp_token;
do_aggr ();
/* fall through to output... */
case ENUM:
/* Set this again, in case we are rescanning. */
looking_for_typename = 1;
/* fall through... */
default:
consume_token();
}
yylval = tmp_token.yylval;
yychar = tmp_token.yychar;
end_of_file = tmp_token.end_of_file;
#ifdef SPEW_DEBUG
if (spew_debug)
debug_yychar(yychar);
#endif
return yychar;
}
/* token[0] == AGGR (struct/union/enum)
* Thus, token[1] is either a TYPENAME or a TYPENAME_DEFN.
* If token[2] == '{' or ':' then it's TYPENAME_DEFN.
* It's also a definition if it's a forward declaration (as in 'struct Foo;')
* which we can tell lf token[2] == ';' *and* token[-1] != FRIEND.
*/
static int
do_aggr ()
{
int yc1, yc2;
scan_tokens (2);
yc1 = nth_token (1)->yychar;
if (yc1 != TYPENAME && yc1 != IDENTIFIER && yc1 != PTYPENAME)
return 0;
yc2 = nth_token (2)->yychar;
if (yc2 == ';')
{
/* It's a forward declaration iff we were not preceded by 'friend'. */
if (first_token > 0 && nth_token (-1)->yychar == SCSPEC
&& nth_token (-1)->yylval.ttype == ridpointers[(int) RID_FRIEND])
return 0;
}
else if (yc2 != '{' && yc2 != ':')
return 0;
switch (yc1)
{
case TYPENAME:
nth_token (1)->yychar = TYPENAME_DEFN;
break;
case PTYPENAME:
nth_token (1)->yychar = PTYPENAME_DEFN;
break;
case IDENTIFIER:
nth_token (1)->yychar = IDENTIFIER_DEFN;
break;
default:
my_friendly_abort (102);
}
return 0;
}
#ifdef SPEW_DEBUG
/* debug_yychar takes a yychar (token number) value and prints its name. */
static int
debug_yychar (yy)
int yy;
{
/* In parse.y: */
extern char *debug_yytranslate ();
int i;
if(yy<256) {
fprintf (stderr, "<%d: %c >\n", yy, yy);
return 0;
}
fprintf (stderr, "<%d:%s>\n", yy, debug_yytranslate (yy));
return 1;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,103 @@
/* This file contains the definitions and documentation for the
additional tree codes used in the GNU C++ compiler (see tree.def
for the standard codes).
Copyright (C) 1987, 1988, 1990, 1993 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Reference to the contents of an offset
(a value whose type is an OFFSET_TYPE).
Operand 0 is the object within which the offset is taken.
Operand 1 is the offset. The language independent OFFSET_REF
just won't work for us. */
DEFTREECODE (CP_OFFSET_REF, "cp_offset_ref", "r", 2)
/* For DELETE_EXPR, operand 0 is the store to be destroyed.
Operand 1 is the value to pass to the destroying function
saying whether the store should be deallocated as well. */
DEFTREECODE (DELETE_EXPR, "dl_expr", "e", 2)
DEFTREECODE (VEC_DELETE_EXPR, "vec_dl_expr", "e", 2)
/* Value is reference to particular overloaded class method.
Operand 0 is the class name (an IDENTIFIER_NODE);
operand 1 is the field (also an IDENTIFIER_NODE).
The COMPLEXITY field holds the class level (usually 0). */
DEFTREECODE (SCOPE_REF, "scope_ref", "r", 2)
/* When composing an object with a member, this is the result.
Operand 0 is the object. Operand 1 is the member (usually
a dereferenced pointer to member). */
DEFTREECODE (MEMBER_REF, "member_ref", "r", 2)
/* Type conversion operator in C++. TREE_TYPE is type that this
operator converts to. Operand is expression to be converted. */
DEFTREECODE (TYPE_EXPR, "type_expr", "e", 1)
/* For CPLUS_NEW_EXPR, operand 0 is function which performs initialization,
operand 1 is argument list to initialization function,
and operand 2 is the slot which was allocated for this expression. */
DEFTREECODE (NEW_EXPR, "nw_expr", "e", 3)
DEFTREECODE (VEC_NEW_EXPR, "vec_nw_expr", "e", 3)
/* A throw expression. operand 0 is the expression, if there was one,
else it is NULL_TREE. */
DEFTREECODE (THROW_EXPR, "throw_expr", "e", 1)
/* Template definition. The following fields have the specified uses,
although there are other macros in cp-tree.h that should be used for
accessing this data.
DECL_ARGUMENTS template parm vector
DECL_TEMPLATE_INFO template text &c
DECL_VINDEX list of instantiations already produced;
only done for functions so far
For class template:
DECL_INITIAL associated templates (methods &c)
DECL_RESULT null
For non-class templates:
TREE_TYPE type of object to be constructed
DECL_RESULT decl for object to be created
(e.g., FUNCTION_DECL with tmpl parms used)
*/
DEFTREECODE (TEMPLATE_DECL, "template_decl", "d", 0)
/* Index into a template parameter list. This parameter must be a type.
Use TYPE_FIELDS to find parmlist and index. */
DEFTREECODE (TEMPLATE_TYPE_PARM, "template_type_parm", "t", 0)
/* Index into a template parameter list. This parameter must not be a
type. */
DEFTREECODE (TEMPLATE_CONST_PARM, "template_const_parm", "c", 2)
/* For uninstantiated parameterized types.
TYPE_VALUES tree list:
TREE_PURPOSE template decl
TREE_VALUE parm vector
TREE_CHAIN null
Other useful fields to be defined later. */
DEFTREECODE (UNINSTANTIATED_P_TYPE, "uninstantiated_p_type", "t", 0)
/* A thunk is a stub function.
Thunks are used to implement multiple inheritance:
At run-time, such a thunk subtracts THUNK_DELTA (an int, not a tree)
from the this pointer, and then jumps to DECL_INITIAL
(which is an ADDR_EXPR whose operand is a FUNCTION_DECL).
Other kinds of thunks may be defined later. */
DEFTREECODE (THUNK_DECL, "thunk_decl", "d", 0)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,839 @@
/* Code for handling XREF output from GNU C++.
Copyright (C) 1992, 1993 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include "tree.h"
#include <stdio.h>
#include "cp-tree.h"
#include "input.h"
#include <ctype.h>
extern char *getpwd ();
extern char *index ();
extern char *rindex ();
/* The character(s) used to join a directory specification (obtained with
getwd or equivalent) with a non-absolute file name. */
#ifndef FILE_NAME_JOINER
#define FILE_NAME_JOINER "/"
#endif
/* Nonzero if NAME as a file name is absolute. */
#ifndef FILE_NAME_ABSOLUTE_P
#define FILE_NAME_ABSOLUTE_P(NAME) (NAME[0] == '/')
#endif
/* For cross referencing. */
int flag_gnu_xref;
/************************************************************************/
/* */
/* Common definitions */
/* */
/************************************************************************/
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NULL
#define NULL 0
#endif
#define PALLOC(typ) ((typ *) calloc(1,sizeof(typ)))
/* Return a malloc'd copy of STR. */
#define SALLOC(str) \
((char *) ((str) == NULL ? NULL \
: (char *) strcpy ((char *) malloc (strlen ((str)) + 1), (str))))
#define SFREE(str) (str != NULL && (free(str),0))
#define STREQL(s1,s2) (strcmp((s1),(s2)) == 0)
#define STRNEQ(s1,s2) (strcmp((s1),(s2)) != 0)
#define STRLSS(s1,s2) (strcmp((s1),(s2)) < 0)
#define STRLEQ(s1,s2) (strcmp((s1),(s2)) <= 0)
#define STRGTR(s1,s2) (strcmp((s1),(s2)) > 0)
#define STRGEQ(s1,s2) (strcmp((s1),(s2)) >= 0)
/************************************************************************/
/* */
/* Type definitions */
/* */
/************************************************************************/
typedef struct _XREF_FILE * XREF_FILE;
typedef struct _XREF_SCOPE * XREF_SCOPE;
typedef struct _XREF_FILE
{
char *name;
char *outname;
XREF_FILE next;
} XREF_FILE_INFO;
typedef struct _XREF_SCOPE
{
int gid;
int lid;
XREF_FILE file;
int start;
XREF_SCOPE outer;
} XREF_SCOPE_INFO;
/************************************************************************/
/* */
/* Local storage */
/* */
/************************************************************************/
static char doing_xref = 0;
static FILE * xref_file = NULL;
static char xref_name[1024];
static XREF_FILE all_files = NULL;
static char * wd_name = NULL;
static XREF_SCOPE cur_scope = NULL;
static int scope_ctr = 0;
static XREF_FILE last_file = NULL;
static tree last_fndecl = NULL;
/************************************************************************/
/* */
/* Forward definitions */
/* */
/************************************************************************/
extern void GNU_xref_begin();
extern void GNU_xref_end();
extern void GNU_xref_file();
extern void GNU_xref_start_scope();
extern void GNU_xref_end_scope();
extern void GNU_xref_ref();
extern void GNU_xref_decl();
extern void GNU_xref_call();
extern void GNU_xref_function();
extern void GNU_xref_assign();
extern void GNU_xref_hier();
extern void GNU_xref_member();
static void gen_assign();
static XREF_FILE find_file();
static char * filename();
static char * fctname();
static char * declname();
static void simplify_type();
static char * fixname();
static void open_xref_file();
extern char * type_as_string();
/* Start cross referencing. FILE is the name of the file we xref. */
void
GNU_xref_begin (file)
char *file;
{
doing_xref = 1;
if (file != NULL && STRNEQ (file,"-"))
{
open_xref_file(file);
GNU_xref_file(file);
}
}
/* Finish cross-referencing. ERRCNT is the number of errors
we encountered. */
void
GNU_xref_end (ect)
int ect;
{
XREF_FILE xf;
if (!doing_xref) return;
xf = find_file (input_filename);
if (xf == NULL) return;
while (cur_scope != NULL)
GNU_xref_end_scope(cur_scope->gid,0,0,0,0);
doing_xref = 0;
if (xref_file == NULL) return;
fclose (xref_file);
xref_file = NULL;
all_files = NULL;
if (ect > 0) unlink (xref_name);
}
/* Write out xref for file named NAME. */
void
GNU_xref_file (name)
char *name;
{
XREF_FILE xf;
if (!doing_xref || name == NULL) return;
if (xref_file == NULL)
{
open_xref_file (name);
if (!doing_xref) return;
}
if (all_files == NULL)
fprintf(xref_file,"SCP * 0 0 0 0 RESET\n");
xf = find_file (name);
if (xf != NULL) return;
xf = PALLOC (XREF_FILE_INFO);
xf->name = SALLOC (name);
xf->next = all_files;
all_files = xf;
if (wd_name == NULL)
wd_name = getpwd ();
if (FILE_NAME_ABSOLUTE_P (name) || ! wd_name)
xf->outname = xf->name;
else
{
char *nmbuf
= (char *) malloc (strlen (wd_name) + strlen (FILE_NAME_JOINER)
+ strlen (name) + 1);
sprintf (nmbuf, "%s%s%s", wd_name, FILE_NAME_JOINER, name);
name = nmbuf;
xf->outname = nmbuf;
}
fprintf (xref_file, "FIL %s %s 0\n", name, wd_name);
filename (xf);
fctname (NULL);
}
/* Start a scope identified at level ID. */
void
GNU_xref_start_scope (id)
HOST_WIDE_INT id;
{
XREF_SCOPE xs;
XREF_FILE xf;
if (!doing_xref) return;
xf = find_file (input_filename);
xs = PALLOC (XREF_SCOPE_INFO);
xs->file = xf;
xs->start = lineno;
if (xs->start <= 0) xs->start = 1;
xs->gid = id;
xs->lid = ++scope_ctr;
xs->outer = cur_scope;
cur_scope = xs;
}
/* Finish a scope at level ID.
INID is ???
PRM is ???
KEEP is nonzero iff this scope is retained (nonzero if it's
a compiler-generated invisible scope).
TRNS is ??? */
void
GNU_xref_end_scope (id,inid,prm,keep,trns)
HOST_WIDE_INT id;
HOST_WIDE_INT inid;
int prm,keep,trns;
{
XREF_FILE xf;
XREF_SCOPE xs,lxs,oxs;
char *stype;
if (!doing_xref) return;
xf = find_file (input_filename);
if (xf == NULL) return;
lxs = NULL;
for (xs = cur_scope; xs != NULL; xs = xs->outer)
{
if (xs->gid == id) break;
lxs = xs;
}
if (xs == NULL) return;
if (inid != 0) {
for (oxs = cur_scope; oxs != NULL; oxs = oxs->outer) {
if (oxs->gid == inid) break;
}
if (oxs == NULL) return;
inid = oxs->lid;
}
if (prm == 2) stype = "SUE";
else if (prm != 0) stype = "ARGS";
else if (keep == 2 || inid != 0) stype = "INTERN";
else stype = "EXTERN";
fprintf (xref_file,"SCP %s %d %d %d %d %s\n",
filename (xf), xs->start, lineno,xs->lid, inid, stype);
if (lxs == NULL) cur_scope = xs->outer;
else lxs->outer = xs->outer;
free (xs);
}
/* Output a reference to NAME in FNDECL. */
void
GNU_xref_ref (fndecl,name)
tree fndecl;
char *name;
{
XREF_FILE xf;
if (!doing_xref) return;
xf = find_file (input_filename);
if (xf == NULL) return;
fprintf (xref_file, "REF %s %d %s %s\n",
filename (xf), lineno, fctname (fndecl), name);
}
/* Output a reference to DECL in FNDECL. */
void
GNU_xref_decl (fndecl,decl)
tree fndecl;
tree decl;
{
XREF_FILE xf,xf1;
char *cls;
char *name;
char buf[10240];
int uselin;
if (!doing_xref) return;
xf = find_file (input_filename);
if (xf == NULL) return;
uselin = FALSE;
if (TREE_CODE (decl) == TYPE_DECL) cls = "TYPEDEF";
else if (TREE_CODE (decl) == FIELD_DECL) cls = "FIELD";
else if (TREE_CODE (decl) == VAR_DECL)
{
if (fndecl == NULL && TREE_STATIC(decl)
&& TREE_READONLY(decl) && DECL_INITIAL(decl) != 0
&& !TREE_PUBLIC(decl) && !DECL_EXTERNAL(decl)
&& DECL_MODE(decl) != BLKmode) cls = "CONST";
else if (DECL_EXTERNAL(decl)) cls = "EXTERN";
else if (TREE_PUBLIC(decl)) cls = "EXTDEF";
else if (TREE_STATIC(decl)) cls = "STATIC";
else if (DECL_REGISTER(decl)) cls = "REGISTER";
else cls = "AUTO";
}
else if (TREE_CODE (decl) == PARM_DECL) cls = "PARAM";
else if (TREE_CODE (decl) == FIELD_DECL) cls = "FIELD";
else if (TREE_CODE (decl) == CONST_DECL) cls = "CONST";
else if (TREE_CODE (decl) == FUNCTION_DECL)
{
if (DECL_EXTERNAL (decl)) cls = "EXTERN";
else if (TREE_PUBLIC (decl)) cls = "EFUNCTION";
else cls = "SFUNCTION";
}
else if (TREE_CODE (decl) == LABEL_DECL) cls = "LABEL";
else if (TREE_CODE (decl) == UNION_TYPE)
{
cls = "UNIONID";
decl = TYPE_NAME (decl);
uselin = TRUE;
}
else if (TREE_CODE (decl) == RECORD_TYPE)
{
if (CLASSTYPE_DECLARED_CLASS (decl)) cls = "CLASSID";
else if (IS_SIGNATURE (decl)) cls = "SIGNATUREID";
else cls = "STRUCTID";
decl = TYPE_NAME (decl);
uselin = TRUE;
}
else if (TREE_CODE (decl) == ENUMERAL_TYPE)
{
cls = "ENUMID";
decl = TYPE_NAME (decl);
uselin = TRUE;
}
else if (TREE_CODE (decl) == TEMPLATE_DECL)
{
if (DECL_TEMPLATE_IS_CLASS (decl))
cls = "CLASSTEMP";
else if (TREE_CODE (DECL_RESULT (decl)) == FUNCTION_DECL)
cls = "FUNCTEMP";
else if (TREE_CODE (DECL_RESULT (decl)) == VAR_DECL)
cls = "VARTEMP";
else
my_friendly_abort (358);
uselin = TRUE;
}
else cls = "UNKNOWN";
if (decl == NULL || DECL_NAME (decl) == NULL) return;
if (uselin && decl->decl.linenum > 0 && decl->decl.filename != NULL)
{
xf1 = find_file (decl->decl.filename);
if (xf1 != NULL)
{
lineno = decl->decl.linenum;
xf = xf1;
}
}
if (DECL_ASSEMBLER_NAME (decl))
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
else
name = IDENTIFIER_POINTER (DECL_NAME (decl));
strcpy (buf, type_as_string (TREE_TYPE (decl), 0));
simplify_type (buf);
fprintf (xref_file, "DCL %s %d %s %d %s %s %s\n",
filename(xf), lineno, name,
(cur_scope != NULL ? cur_scope->lid : 0),
cls, fctname(fndecl), buf);
if (STREQL (cls, "STRUCTID") || STREQL (cls, "UNIONID")
|| STREQL (cls, "SIGNATUREID"))
{
cls = "CLASSID";
fprintf (xref_file, "DCL %s %d %s %d %s %s %s\n",
filename(xf), lineno,name,
(cur_scope != NULL ? cur_scope->lid : 0),
cls, fctname(fndecl), buf);
}
}
/* Output a reference to a call to NAME in FNDECL. */
void
GNU_xref_call (fndecl, name)
tree fndecl;
char *name;
{
XREF_FILE xf;
char buf[1024];
char *s;
if (!doing_xref) return;
xf = find_file (input_filename);
if (xf == NULL) return;
name = fixname (name, buf);
for (s = name; *s != 0; ++s)
if (*s == '_' && s[1] == '_') break;
if (*s != 0) GNU_xref_ref (fndecl, name);
fprintf (xref_file, "CAL %s %d %s %s\n",
filename (xf), lineno, name, fctname (fndecl));
}
/* Output cross-reference info about FNDECL. If non-NULL,
ARGS are the arguments for the function (i.e., before the FUNCTION_DECL
has been fully built). */
void
GNU_xref_function (fndecl, args)
tree fndecl;
tree args;
{
XREF_FILE xf;
int ct;
char buf[1024];
if (!doing_xref) return;
xf = find_file (input_filename);
if (xf == NULL) return;
ct = 0;
buf[0] = 0;
if (args == NULL) args = DECL_ARGUMENTS (fndecl);
GNU_xref_decl (NULL, fndecl);
for ( ; args != NULL; args = TREE_CHAIN (args))
{
GNU_xref_decl (fndecl,args);
if (ct != 0) strcat (buf,",");
strcat (buf, declname (args));
++ct;
}
fprintf (xref_file, "PRC %s %d %s %d %d %s\n",
filename(xf), lineno, declname(fndecl),
(cur_scope != NULL ? cur_scope->lid : 0),
ct, buf);
}
/* Output cross-reference info about an assignment to NAME. */
void
GNU_xref_assign(name)
tree name;
{
XREF_FILE xf;
if (!doing_xref) return;
xf = find_file(input_filename);
if (xf == NULL) return;
gen_assign(xf, name);
}
static void
gen_assign(xf, name)
XREF_FILE xf;
tree name;
{
char *s;
s = NULL;
switch (TREE_CODE (name))
{
case IDENTIFIER_NODE :
s = IDENTIFIER_POINTER(name);
break;
case VAR_DECL :
s = declname(name);
break;
case COMPONENT_REF :
gen_assign(xf, TREE_OPERAND(name, 0));
gen_assign(xf, TREE_OPERAND(name, 1));
break;
case INDIRECT_REF :
case OFFSET_REF :
case ARRAY_REF :
case BUFFER_REF :
gen_assign(xf, TREE_OPERAND(name, 0));
break;
case COMPOUND_EXPR :
gen_assign(xf, TREE_OPERAND(name, 1));
break;
default :
break;
}
if (s != NULL)
fprintf(xref_file, "ASG %s %d %s\n", filename(xf), lineno, s);
}
/* Output cross-reference info about a class hierarchy.
CLS is the class type of interest. BASE is a baseclass
for CLS. PUB and VIRT give the access info about
the class derivation. FRND is nonzero iff BASE is a friend
of CLS.
??? Needs to handle nested classes. */
void
GNU_xref_hier(cls, base, pub, virt, frnd)
char *cls;
char *base;
int pub;
int virt;
int frnd;
{
XREF_FILE xf;
if (!doing_xref) return;
xf = find_file(input_filename);
if (xf == NULL) return;
fprintf(xref_file, "HIE %s %d %s %s %d %d %d\n",
filename(xf), lineno, cls, base, pub, virt, frnd);
}
/* Output cross-reference info about class members. CLS
is the containing type; FLD is the class member. */
void
GNU_xref_member(cls, fld)
tree cls;
tree fld;
{
XREF_FILE xf;
char *prot;
int confg, pure;
char *d;
int i;
char buf[1024], bufa[1024];
if (!doing_xref) return;
xf = find_file(fld->decl.filename);
if (xf == NULL) return;
if (TREE_PRIVATE (fld)) prot = "PRIVATE";
else if (TREE_PROTECTED(fld)) prot = "PROTECTED";
else prot = "PUBLIC";
confg = 0;
if (TREE_CODE (fld) == FUNCTION_DECL && DECL_CONST_MEMFUNC_P(fld))
confg = 1;
else if (TREE_CODE (fld) == CONST_DECL)
confg = 1;
pure = 0;
if (TREE_CODE (fld) == FUNCTION_DECL && DECL_ABSTRACT_VIRTUAL_P(fld))
pure = 1;
d = IDENTIFIER_POINTER(cls);
sprintf(buf, "%d%s", strlen(d), d);
i = strlen(buf);
strcpy(bufa, declname(fld));
#ifdef XREF_SHORT_MEMBER_NAMES
for (p = &bufa[1]; *p != 0; ++p)
{
if (p[0] == '_' && p[1] == '_' && p[2] >= '0' && p[2] <= '9') {
if (strncmp(&p[2], buf, i) == 0) *p = 0;
break;
}
else if (p[0] == '_' && p[1] == '_' && p[2] == 'C' && p[3] >= '0' && p[3] <= '9') {
if (strncmp(&p[3], buf, i) == 0) *p = 0;
break;
}
}
#endif
fprintf(xref_file, "MEM %s %d %s %s %s %d %d %d %d %d %d %d\n",
filename(xf), fld->decl.linenum, d, bufa, prot,
(TREE_CODE (fld) == FUNCTION_DECL ? 0 : 1),
(DECL_INLINE (fld) ? 1 : 0),
(DECL_FRIEND_P(fld) ? 1 : 0),
(DECL_VINDEX(fld) ? 1 : 0),
(TREE_STATIC(fld) ? 1 : 0),
pure, confg);
}
/* Find file entry given name. */
static XREF_FILE
find_file(name)
char *name;
{
XREF_FILE xf;
for (xf = all_files; xf != NULL; xf = xf->next) {
if (STREQL(name, xf->name)) break;
}
return xf;
}
/* Return filename for output purposes. */
static char *
filename(xf)
XREF_FILE xf;
{
if (xf == NULL) {
last_file = NULL;
return "*";
}
if (last_file == xf) return "*";
last_file = xf;
return xf->outname;
}
/* Return function name for output purposes. */
static char *
fctname(fndecl)
tree fndecl;
{
static char fctbuf[1024];
char *s;
if (fndecl == NULL && last_fndecl == NULL) return "*";
if (fndecl == NULL)
{
last_fndecl = NULL;
return "*TOP*";
}
if (fndecl == last_fndecl) return "*";
last_fndecl = fndecl;
s = declname(fndecl);
s = fixname(s, fctbuf);
return s;
}
/* Return decl name for output purposes. */
static char *
declname(dcl)
tree dcl;
{
if (DECL_NAME (dcl) == NULL) return "?";
if (DECL_ASSEMBLER_NAME (dcl))
return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (dcl));
else
return IDENTIFIER_POINTER (DECL_NAME (dcl));
}
/* Simplify a type string by removing unneeded parenthesis. */
static void
simplify_type(typ)
char *typ;
{
char *s;
int lvl, i;
i = strlen(typ);
while (i > 0 && isspace(typ[i-1])) typ[--i] = 0;
if (i > 7 && STREQL(&typ[i-5], "const"))
{
typ[i-5] = 0;
i -= 5;
}
if (typ[i-1] != ')') return;
s = &typ[i-2];
lvl = 1;
while (*s != 0) {
if (*s == ')') ++lvl;
else if (*s == '(')
{
--lvl;
if (lvl == 0)
{
s[1] = ')';
s[2] = 0;
break;
}
}
--s;
}
if (*s != 0 && s[-1] == ')')
{
--s;
--s;
if (*s == '(') s[2] = 0;
else if (*s == ':') {
while (*s != '(') --s;
s[1] = ')';
s[2] = 0;
}
}
}
/* Fixup a function name (take care of embedded spaces). */
static char *
fixname(nam, buf)
char *nam;
char *buf;
{
char *s, *t;
int fg;
s = nam;
t = buf;
fg = 0;
while (*s != 0)
{
if (*s == ' ')
{
*t++ = '\36';
++fg;
}
else *t++ = *s;
++s;
}
*t = 0;
if (fg == 0) return nam;
return buf;
}
/* Open file for xrefing. */
static void
open_xref_file(file)
char *file;
{
char *s, *t;
#ifdef XREF_FILE_NAME
XREF_FILE_NAME (xref_name, file);
#else
s = rindex (file, '/');
if (s == NULL)
sprintf (xref_name, ".%s.gxref", file);
else
{
++s;
strcpy (xref_name, file);
t = rindex (xref_name, '/');
++t;
*t++ = '.';
strcpy (t, s);
strcat (t, ".gxref");
}
#endif /* no XREF_FILE_NAME */
xref_file = fopen(xref_name, "w");
if (xref_file == NULL)
{
error("Can't create cross-reference file `%s'", xref_name);
doing_xref = 0;
}
}

View File

@ -0,0 +1,12 @@
#
# $FreeBSD$
#
SRCS = aux-output.c bc-emit.c bc-optab.c c-common.c caller-save.c calls.c combine.c convert.c cse.c dbxout.c dwarfout.c emit-rtl.c explow.c expmed.c expr.c final.c flow.c fold-const.c function.c getpwd.c global.c insn-attrtab.c insn-emit.c insn-extract.c insn-opinit.c insn-output.c insn-peep.c insn-recog.c integrate.c jump.c local-alloc.c loop.c obstack.c optabs.c print-rtl.c print-tree.c real.c recog.c reg-stack.c regclass.c reload.c reload1.c reorg.c rtl.c rtlanal.c sched.c sdbout.c stmt.c stor-layout.c stupid.c toplev.c tree.c unroll.c varasm.c version.c xcoffout.c
LIB = cc_int
NOPROFILE= 1
install:
@true
.include <bsd.lib.mk>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,991 @@
/* Output bytecodes for GNU C-compiler.
Copyright (C) 1993, 1994 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "machmode.h"
#include "rtl.h"
#include "real.h"
#include "obstack.h"
#include "bytecode.h"
#ifdef __GNUC__
#include "bytetypes.h"
#endif
#include "bc-emit.h"
#include "bc-opcode.h"
#include "bc-typecd.h"
#include "bi-run.h"
#include <stdio.h>
extern char *xmalloc (), *xrealloc ();
extern void free ();
extern struct obstack *rtl_obstack;
/* Indexed by mode class, gives the narrowest mode for each class. */
extern enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS];
/* Commonly used modes. */
/* Mode whose width is BITS_PER_UNIT */
extern enum machine_mode byte_mode;
/* Mode whose width is BITS_PER_WORD */
extern enum machine_mode word_mode;
/* Vector indexed by opcode giving info about the args for each opcode. */
static struct arityvec arityvec[] = {
#include "bc-arity.h"
};
/* How to print a symbol name for the assembler. */
static void
prsym (file, s)
FILE *file;
char *s;
{
if (*s == '*')
fprintf (file, "%s", s + 1);
else
#ifdef NAMES_HAVE_UNDERSCORES
fprintf (file, "_%s", s);
#else
fprintf (file, "%s", s);
#endif
}
/* Maintain a bucket hash table for symbol names. */
#define HASH_BITS 32
#define HASH_SIZE 509
static struct bc_sym *hashtab[HASH_SIZE];
static unsigned int
hash (name)
char *name;
{
unsigned int hash = 0;
while (*name)
{
hash = hash << 3 | hash >> HASH_BITS - 3;
hash += *name++;
}
return hash % HASH_SIZE;
}
/* Look up the named symbol, creating it if it doesn't exist. */
struct bc_sym *
sym_lookup (name)
char *name;
{
int i;
struct bc_sym *s;
i = hash (name);
for (s = hashtab[i]; s; s = s->next)
if (!strcmp (s->name, name))
return s;
s = (struct bc_sym *) xmalloc (sizeof (struct bc_sym));
s->name = xmalloc (strlen (name) + 1);
strcpy (s->name, name);
s->defined = s->global = s->common = 0;
s->val = 0;
s->next = hashtab[i];
hashtab[i] = s;
return s;
}
/* Write out .globl and common symbols to the named file. */
static void
bc_sym_write (file)
FILE *file;
{
int i;
struct bc_sym *s;
for (i = 0; i < HASH_SIZE; ++i)
for (s = hashtab[i]; s; s = s->next)
{
if (s->global)
{
fprintf (file, "\n\t.globl ");
prsym (file, s->name);
putc ('\n', file);
if (s->common)
{
fprintf (file, "\n\t.comm ");
prsym (file, s->name);
fprintf (file, ", %d\n", s->val);
}
}
else if (s->common)
{
fprintf (file, "\n\t.lcomm ");
prsym (file, s->name);
fprintf (file, ", %d\n", s->val);
}
}
}
/* Create and initialize a new segment. */
static struct bc_seg *
seg_create ()
{
struct bc_seg *result;
result = (struct bc_seg *) xmalloc (sizeof (struct bc_seg));
result->alloc = 256;
result->data = xmalloc (result->alloc);
result->size = 0;
result->syms = 0;
result->relocs = 0;
return result;
}
/* Advance the segment index to the next alignment boundary. */
static void
seg_align (seg, log)
struct bc_seg *seg;
int log;
{
unsigned int oldsize = seg->size;
seg->size = seg->size + (1 << log) - 1 & ~((1 << log) - 1);
if (seg->size > seg->alloc)
{
while (seg->size > seg->alloc)
seg->alloc *= 2;
seg->data = xrealloc (seg->data, seg->alloc);
}
bzero (seg->data + oldsize, seg->size - oldsize);
}
/* Append the given data to the given segment. */
static void
seg_data (seg, data, size)
struct bc_seg *seg;
char *data;
unsigned int size;
{
if (seg->size + size > seg->alloc)
{
while (seg->size + size > seg->alloc)
seg->alloc *= 2;
seg->data = xrealloc (seg->data, seg->alloc);
}
bcopy (data, seg->data + seg->size, size);
seg->size += size;
}
/* Append a zero-filled skip to the given segment. */
static void
seg_skip (seg, size)
struct bc_seg *seg;
unsigned int size;
{
if (seg->size + size > seg->alloc)
{
while (seg->size + size > seg->alloc)
seg->alloc *= 2;
seg->data = xrealloc (seg->data, seg->alloc);
}
memset (seg->data + seg->size, 0, size);
seg->size += size;
}
/* Define the given name as the current offset in the given segment. It
is an error if the name is already defined. Return 0 or 1 indicating
failure or success respectively. */
static int
seg_defsym (seg, name)
struct bc_seg *seg;
char *name;
{
struct bc_sym *sym;
struct bc_segsym *segsym;
sym = sym_lookup (name);
if (sym->defined)
return 0;
sym->defined = 1;
sym->val = seg->size;
segsym = (struct bc_segsym *) xmalloc (sizeof (struct bc_segsym));
segsym->sym = sym;
segsym->next = seg->syms;
seg->syms = segsym;
return 1;
}
/* Generate in seg's data a reference to the given sym, adjusted by
the given offset. */
static void
seg_refsym (seg, name, offset)
struct bc_seg *seg;
char *name;
int offset;
{
struct bc_sym *sym;
struct bc_segreloc *segreloc;
sym = sym_lookup (name);
segreloc = (struct bc_segreloc *) xmalloc (sizeof (struct bc_segreloc));
segreloc->offset = seg->size;
segreloc->sym = sym;
segreloc->next = seg->relocs;
seg->relocs = segreloc;
seg_data (seg, (char *) &offset, sizeof offset);
}
/* Concatenate the contents of given segments into the first argument. */
static void
seg_concat (result, seg)
struct bc_seg *result, *seg;
{
unsigned int fix;
struct bc_segsym *segsym;
struct bc_segreloc *segreloc;
seg_align (result, MACHINE_SEG_ALIGN);
fix = result->size;
seg_data (result, seg->data, seg->size);
free (seg->data);
/* Go through the symbols and relocs of SEG, adjusting their offsets
for their new location in RESULT. */
if (seg->syms)
{
segsym = seg->syms;
do
segsym->sym->val += fix;
while (segsym->next && (segsym = segsym->next));
segsym->next = result->syms;
result->syms = seg->syms;
}
if (seg->relocs)
{
segreloc = seg->relocs;
do
segreloc->offset += fix;
while (segreloc->next && (segreloc = segreloc->next));
segreloc->next = result->relocs;
result->relocs = seg->relocs;
}
free ((char *) seg);
}
/* Write a segment to a file. */
static void
bc_seg_write (seg, file)
struct bc_seg *seg;
FILE *file;
{
struct bc_segsym *segsym, *nsegsym, *psegsym;
struct bc_segreloc *segreloc, *nsegreloc, *psegreloc;
int i, offset, flag;
/* Reverse the list of symbols. */
for (psegsym = 0, segsym = seg->syms; segsym; segsym = nsegsym)
{
nsegsym = segsym->next;
segsym->next = psegsym;
psegsym = segsym;
}
seg->syms = psegsym;
/* Reverse the list of relocs. */
for (psegreloc = 0, segreloc = seg->relocs; segreloc; segreloc = nsegreloc)
{
nsegreloc = segreloc->next;
segreloc->next = psegreloc;
psegreloc = segreloc;
}
seg->relocs = psegreloc;
/* Output each byte of the segment. */
for (i = 0, segsym = seg->syms, segreloc = seg->relocs; i < seg->size; ++i)
{
while (segsym && segsym->sym->val == i)
{
if (i % 8 != 0)
putc ('\n', file);
BC_WRITE_SEGSYM (segsym, file);
segsym = segsym->next;
flag = 1;
}
if (segreloc && segreloc->offset == i)
{
if (i % 8 != 0)
putc ('\n', file);
bcopy (seg->data + i, (char *) &offset, sizeof (int));
i += sizeof (int) - 1;
BC_WRITE_RELOC_ENTRY (segreloc, file, offset);
segreloc = segreloc->next;
flag = 1;
}
else
{
if (i % 8 == 0 || flag)
BC_START_BYTECODE_LINE (file);
BC_WRITE_BYTECODE (i % 8 == 0 || flag ? ' ' : ',',
seg->data[i] & 0xFF,
file);
flag = 0;
if (i % 8 == 7)
putc ('\n', file);
}
}
/* Paranoia check--we should have visited all syms and relocs during
the output pass. */
if (segsym || segreloc)
abort ();
}
/* Text and data segments of the object file in making. */
static struct bc_seg *bc_text_seg;
static struct bc_seg *bc_data_seg;
/* Called before anything else in this module. */
void
bc_initialize ()
{
int min_class_size[(int) MAX_MODE_CLASS];
enum machine_mode mode;
int i;
bc_init_mode_to_code_map ();
bc_text_seg = seg_create ();
bc_data_seg = seg_create ();
dconst0 = REAL_VALUE_ATOF ("0", DFmode);
dconst1 = REAL_VALUE_ATOF ("1", DFmode);
dconst2 = REAL_VALUE_ATOF ("2", DFmode);
dconstm1 = REAL_VALUE_ATOF ("-1", DFmode);
/* Find the narrowest mode for each class and compute the word and byte
modes. */
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);
}
if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) == BITS_PER_UNIT)
byte_mode = mode;
if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) == BITS_PER_WORD)
word_mode = mode;
}
}
/* External addresses referenced in a function. Rather than trying to
work relocatable address directly into bytecoded functions (which would
require us to provide hairy location info and possibly obey alignment
rules imposed by the architecture) we build an auxilary table of
pointer constants, and encode just offsets into this table into the
actual bytecode. */
static struct bc_seg *ptrconsts;
/* Trampoline code for the function entry. */
struct bc_seg *trampoline;
/* Actual byte code of the function. */
struct bc_seg *bytecode;
/* List of labels defined in the function. */
struct bc_label *labels;
/* List of label references in the function. */
struct bc_labelref *labelrefs;
/* Add symbol to pointer table. Return offset into table where
pointer was stored. The offset usually goes into the bytecode
stream as a constP literal. */
int
bc_define_pointer (p)
char *p;
{
int offset = ptrconsts->size;
seg_refsym (ptrconsts, p, 0);
return offset;
}
/* Begin a bytecoded function. */
int
bc_begin_function (name)
char *name;
{
ptrconsts = seg_create ();
trampoline = seg_create ();
bytecode = seg_create ();
return seg_defsym (trampoline, name);
}
/* Force alignment in inline bytecode. */
void
bc_align_bytecode (align)
int align;
{
seg_align (bytecode, align);
}
/* Emit data inline into bytecode. */
void
bc_emit_bytecode_const (data, size)
char *data;
unsigned int size;
{
if (bytecode)
seg_data (bytecode, data, size);
}
/* Create a new "bytecode label", to have its value defined later.
Bytecode labels have nothing to do with the object file symbol table,
and are purely local to a given bytecoded function. */
struct bc_label *
bc_get_bytecode_label ()
{
struct bc_label *result;
result = (struct bc_label *) xmalloc (sizeof (struct bc_label));
result->defined = 0;
result->next = labels;
result->uid = 0;
labels = result;
return result;
}
/* Define the given label with the current location counter. */
int
bc_emit_bytecode_labeldef (label)
struct bc_label *label;
{
extern int bc_new_uid ();
if (!label || label->defined)
return 0;
label->offset = bytecode->size;
label->defined = 1;
label->uid = bc_new_uid ();
#ifdef DEBUG_PRINT_CODE
fprintf (stderr, "$%lx:\n", label);
#endif
return 1;
}
/* Generate a location-relative reference to the given bytecode label.
It need not be defined yet; label references will be backpatched later. */
void
bc_emit_bytecode_labelref (label)
struct bc_label *label;
{
struct bc_labelref *labelref;
static int zero;
labelref = (struct bc_labelref *) xmalloc (sizeof (struct bc_labelref));
labelref->label = label;
labelref->offset = bytecode->size;
labelref->next = labelrefs;
labelrefs = labelref;
#ifdef DEBUG_PRINT_CODE
fprintf (stderr, " $%lx", label);
#endif
seg_data (bytecode, (char *) &zero, sizeof zero);
}
/* Emit a reference to an external address; generate the reference in the
ptrconst area, and emit an offset in the bytecode. */
void
bc_emit_code_labelref (name, offset)
char *name;
int offset;
{
int ptroff;
ptroff = ptrconsts->size / sizeof (char *);
seg_data (bytecode, (char *) &ptroff, sizeof ptroff);
seg_refsym (ptrconsts, name, offset);
#ifdef DEBUG_PRINT_CODE
fprintf (stderr, " [external <%x> %s]", ptroff, name);
#endif
}
/* Backpatch label references in the byte code, and concatenate the bytecode
and pointer constant segments to the cumulative text for the object file.
Return a label name for the pointer constants region. */
char *
bc_end_function ()
{
int addr;
struct bc_label *label, *next;
struct bc_labelref *ref, *nextref;
char ptrconsts_label[20];
static int nlab;
/* Backpatch bytecode label references. */
for (ref = labelrefs; ref; ref = ref->next)
if (ref->label->defined)
{
addr = ref->label->offset;
bcopy ((char *) &addr, bytecode->data + ref->offset, sizeof addr);
}
/* Free the chains of labelrefs and labeldefs. */
for (ref = labelrefs; ref; ref = nextref)
{
nextref = ref->next;
free ((char *) ref);
}
for (label = labels; label; label = next)
{
next = label->next;
free ((char *) label);
}
seg_concat (trampoline, bytecode);
seg_align (trampoline, MACHINE_SEG_ALIGN);
sprintf (ptrconsts_label, "*LP%d", nlab++);
seg_defsym (trampoline, ptrconsts_label);
seg_concat (trampoline, ptrconsts);
seg_concat (bc_text_seg, trampoline);
labels = 0;
labelrefs = 0;
trampoline = 0;
bytecode = 0;
ptrconsts = 0;
return sym_lookup (ptrconsts_label)->name;
}
/* Force alignment in const data. */
void
bc_align_const (align)
int align;
{
seg_align (bc_text_seg, align);
}
/* Emit const data. */
void
bc_emit_const (data, size)
char *data;
unsigned int size;
{
seg_data (bc_text_seg, data, size);
}
/* Emit a zero-filled constant skip. */
void
bc_emit_const_skip (size)
unsigned int size;
{
seg_skip (bc_text_seg, size);
}
/* Emit a label definition in const data. */
int
bc_emit_const_labeldef (name)
char *name;
{
return seg_defsym (bc_text_seg, name);
}
/* Emit a label reference in const data. */
void
bc_emit_const_labelref (name, offset)
char *name;
int offset;
{
seg_refsym (bc_text_seg, name, offset);
}
/* Force alignment in data. */
void
bc_align_data (align)
int align;
{
seg_align (bc_data_seg, align);
}
/* Emit data. */
void
bc_emit_data (data, size)
char *data;
unsigned int size;
{
seg_data (bc_data_seg, data, size);
}
/* Emit a zero-filled data skip. */
void
bc_emit_data_skip (size)
unsigned int size;
{
seg_skip (bc_data_seg, size);
}
/* Emit label definition in data. */
int
bc_emit_data_labeldef (name)
char *name;
{
return seg_defsym (bc_data_seg, name);
}
/* Emit label reference in data. */
void
bc_emit_data_labelref (name, offset)
char *name;
int offset;
{
seg_refsym (bc_data_seg, name, offset);
}
/* Emit a common block of the given name and size. Note that
when the .o file is actually written non-global "common"
blocks will have to be turned into space in the data section. */
int
bc_emit_common (name, size)
char *name;
unsigned int size;
{
struct bc_sym *sym;
sym = sym_lookup (name);
if (sym->defined)
return 0;
sym->defined = 1;
sym->common = 1;
sym->val = size;
return 1;
}
/* Globalize the given label. */
void
bc_globalize_label (name)
char *name;
{
struct bc_sym *sym;
sym = sym_lookup (name);
sym->global = 1;
}
static enum { in_text, in_data } section = in_text;
void
bc_text ()
{
section = in_text;
}
void
bc_data ()
{
section = in_data;
}
void
bc_align (align)
int align;
{
if (section == in_text)
bc_align_const (align);
else
bc_align_data (align);
}
void
bc_emit (data, size)
char *data;
unsigned int size;
{
if (section == in_text)
bc_emit_const (data, size);
else
bc_emit_data (data, size);
}
void
bc_emit_skip (size)
unsigned int size;
{
if (section == in_text)
bc_emit_const_skip (size);
else
bc_emit_data_skip (size);
}
int
bc_emit_labeldef (name)
char *name;
{
if (section == in_text)
return bc_emit_const_labeldef (name);
else
return bc_emit_data_labeldef (name);
}
void
bc_emit_labelref (name, offset)
char *name;
int offset;
{
if (section == in_text)
bc_emit_const_labelref (name, offset);
else
bc_emit_data_labelref (name, offset);
}
void
bc_write_file (file)
FILE *file;
{
BC_WRITE_FILE (file);
}
/* Allocate a new bytecode rtx.
If you supply a null BC_LABEL, we generate one. */
rtx
bc_gen_rtx (label, offset, bc_label)
char *label;
int offset;
struct bc_label *bc_label;
{
rtx r;
if (bc_label == 0)
bc_label = (struct bc_label *) xmalloc (sizeof (struct bc_label));
r = gen_rtx (CODE_LABEL, VOIDmode, label, bc_label);
bc_label->offset = offset;
return r;
}
/* Print bytecode rtx */
void
bc_print_rtl (fp, r)
FILE *fp;
rtx r;
{
#if 0 /* This needs to get fixed to really work again. */
/* BC_WRITE_RTL has a definition
that doesn't even make sense for this use. */
BC_WRITE_RTL (r, fp);
#endif
}
/* Emit a bytecode, keeping a running tally of the stack depth. */
void
bc_emit_bytecode (bytecode)
enum bytecode_opcode bytecode;
{
char byte;
static int prev_lineno = -1;
byte = bytecode;
#ifdef BCDEBUG_PRINT_CODE
if (lineno != prev_lineno)
{
fprintf (stderr, "<line %d>\n", lineno);
prev_lineno = lineno;
}
fputs (opcode_name[(unsigned int) bytecode], stderr);
#endif
/* Due to errors we are often requested to output bytecodes that
will cause an interpreter stack undeflow when executed. Instead of
dumping core on such occasions, we omit the bytecode. Erroneous code
should not be executed, regardless. This makes life much easier, since
we don't have to deceive ourselves about the known stack depth. */
bc_emit_bytecode_const (&byte, 1);
if ((stack_depth -= arityvec[(int) bytecode].ninputs) >= 0)
{
if ((stack_depth += arityvec[(int) bytecode].noutputs) > max_stack_depth)
max_stack_depth = stack_depth;
}
#ifdef VALIDATE_STACK_FOR_BC
VALIDATE_STACK_FOR_BC ();
#endif
}
#ifdef BCDEBUG_PRINT_CODE
#define PRLIT(TYPE, PTR) fprintf (stderr, " [%x]", *(TYPE *) PTR)
#else
#define PRLIT(X,Y)
#endif
/* Emit a complete bytecode instruction, expecting the correct number
of literal values in the call. First argument is the instruction, the
remaining arguments are literals of size HOST_WIDE_INT or smaller. */
void
bc_emit_instruction VPROTO((enum bytecode_opcode opcode, ...))
{
#ifndef __STDC__
enum bytecode_opcode opcode;
#endif
va_list arguments;
int nliteral, instruction;
VA_START (arguments, opcode);
#ifndef __STDC__
opcode = va_arg (arguments, enum bytecode_opcode);
#endif
/* Emit instruction bytecode */
bc_emit_bytecode (opcode);
instruction = (int) opcode;
/* Loop literals and emit as bytecode constants */
for (nliteral = 0; nliteral < arityvec[instruction].nliterals; nliteral++)
{
switch (arityvec[instruction].literals[nliteral])
{
/* This conditional is a kludge, but it's necessary
because TYPE might be long long. */
#ifdef __GNUC__
/* Expand definitions into case statements */
#define DEFTYPECODE(CODE, NAME, MODE, TYPE) \
case CODE: \
{ \
TYPE temp = va_arg (arguments, TYPE); \
bc_emit_bytecode_const ((void *) &temp, sizeof temp); \
PRLIT (TYPE, &temp); } \
break;
#include "bc-typecd.def"
#undef DEFTYPECODE
#endif /* __GNUC__ */
default:
abort ();
}
}
#ifdef BCDEBUG_PRINT_CODE
fputc ('\n', stderr);
#endif
}
/* Emit the machine-code interface trampoline at the beginning of a byte
coded function. The argument is a label name of the interpreter
bytecode callinfo structure; the return value is a label name for
the beginning of the actual bytecode. */
char *
bc_emit_trampoline (callinfo)
char *callinfo;
{
char mylab[20];
static int n;
sprintf (mylab, "*LB%d", n++);
BC_EMIT_TRAMPOLINE (trampoline, callinfo);
seg_defsym (bytecode, mylab);
return sym_lookup (mylab)->name;
}
/* Simple strdup */
char *
bc_xstrdup (str)
char *str;
{
char *tmp = xmalloc (strlen (str) + 1);
strcpy (tmp, str);
return tmp;
}

View File

@ -0,0 +1,788 @@
/* Bytecode conversion definitions for GNU C-compiler.
Copyright (C) 1993, 1994 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include "tree.h"
#include "rtl.h"
#include "machmode.h"
#include "obstack.h"
#include "bytecode.h"
#include "bc-typecd.h"
#include "bc-opcode.h"
#include "bc-optab.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
extern char *xmalloc ();
extern void free ();
/* Table relating interpreter typecodes to machine modes. */
#define GET_TYPECODE_MODE(CODE) (typecode_mode[((int) CODE)])
enum machine_mode typecode_mode[] = {
#define DEFTYPECODE(CODE, NAME, MODE, TYPE) MODE,
#include "bc-typecd.def"
#undef DEFTYPECODE
};
/* Machine mode to type code map */
static enum typecode signed_mode_to_code_map[MAX_MACHINE_MODE+1];
static enum typecode unsigned_mode_to_code_map[MAX_MACHINE_MODE+1];
#define GET_TYPECODE_SIZE(CODE) GET_MODE_SIZE (GET_TYPECODE_MODE (CODE))
#define BIG_ARBITRARY_NUMBER 100000
/* Table of recipes for conversions among scalar types, to be filled
in as needed at run time. */
static struct conversion_recipe
{
unsigned char *opcodes; /* Bytecodes to emit in order. */
int nopcodes; /* Count of bytecodes. */
int cost; /* A rather arbitrary cost function. */
} conversion_recipe[NUM_TYPECODES][NUM_TYPECODES];
/* Binary operator tables. */
struct binary_operator optab_plus_expr[] = {
{ addSI, SIcode, SIcode, SIcode },
{ addDI, DIcode, DIcode, DIcode },
{ addSF, SFcode, SFcode, SFcode },
{ addDF, DFcode, DFcode, DFcode },
{ addXF, XFcode, XFcode, XFcode },
{ addPSI, Pcode, Pcode, SIcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_minus_expr[] = {
{ subSI, SIcode, SIcode, SIcode },
{ subDI, DIcode, DIcode, DIcode },
{ subSF, SFcode, SFcode, SFcode },
{ subDF, DFcode, DFcode, DFcode },
{ subXF, XFcode, XFcode, XFcode },
{ subPP, SIcode, Pcode, Pcode },
{ -1, -1, -1, -1 },
};
/* The ordering of the tables for multiplicative operators
is such that unsigned operations will be preferred to signed
operations when one argument is unsigned. */
struct binary_operator optab_mult_expr[] = {
{ mulSU, SUcode, SUcode, SUcode },
{ mulDU, DUcode, DUcode, DUcode },
{ mulSI, SIcode, SIcode, SIcode },
{ mulDI, DIcode, DIcode, DIcode },
{ mulSF, SFcode, SFcode, SFcode },
{ mulDF, DFcode, DFcode, DFcode },
{ mulXF, XFcode, XFcode, XFcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_trunc_div_expr[] = {
{ divSU, SUcode, SUcode, SUcode },
{ divDU, DUcode, DUcode, DUcode },
{ divSI, SIcode, SIcode, SIcode },
{ divDI, DIcode, DIcode, DIcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_trunc_mod_expr[] = {
{ modSU, SUcode, SUcode, SUcode },
{ modDU, DUcode, DUcode, DUcode },
{ modSI, SIcode, SIcode, SIcode },
{ modDI, DIcode, DIcode, DIcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_rdiv_expr[] = {
{ divSF, SFcode, SFcode, SFcode },
{ divDF, DFcode, DFcode, DFcode },
{ divXF, XFcode, XFcode, XFcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_bit_and_expr[] = {
{ andSI, SIcode, SIcode, SIcode },
{ andDI, DIcode, DIcode, DIcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_bit_ior_expr[] = {
{ iorSI, SIcode, SIcode, SIcode },
{ iorDI, DIcode, DIcode, DIcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_bit_xor_expr[] = {
{ xorSI, SIcode, SIcode, SIcode },
{ xorDI, DIcode, DIcode, DIcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_lshift_expr[] = {
{ lshiftSI, SIcode, SIcode, SIcode },
{ lshiftSU, SUcode, SUcode, SIcode },
{ lshiftDI, DIcode, DIcode, SIcode },
{ lshiftDU, DUcode, DUcode, SIcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_rshift_expr[] = {
{ rshiftSI, SIcode, SIcode, SIcode },
{ rshiftSU, SUcode, SUcode, SIcode },
{ rshiftDI, DIcode, DIcode, SIcode },
{ rshiftDU, DUcode, DUcode, SIcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_truth_and_expr[] = {
{ andSI, SIcode, Tcode, Tcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_truth_or_expr[] = {
{ iorSI, SIcode, Tcode, Tcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_lt_expr[] = {
{ ltSI, Tcode, SIcode, SIcode },
{ ltSU, Tcode, SUcode, SUcode },
{ ltDI, Tcode, DIcode, DIcode },
{ ltDU, Tcode, DUcode, DUcode },
{ ltSF, Tcode, SFcode, SFcode },
{ ltDF, Tcode, DFcode, DFcode },
{ ltXF, Tcode, XFcode, XFcode },
{ ltP, Tcode, Pcode, Pcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_le_expr[] = {
{ leSI, Tcode, SIcode, SIcode },
{ leSU, Tcode, SUcode, SUcode },
{ leDI, Tcode, DIcode, DIcode },
{ leDU, Tcode, DUcode, DUcode },
{ leSF, Tcode, SFcode, SFcode },
{ leDF, Tcode, DFcode, DFcode },
{ leXF, Tcode, XFcode, XFcode },
{ leP, Tcode, Pcode, Pcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_ge_expr[] = {
{ geSI, Tcode, SIcode, SIcode },
{ geSU, Tcode, SUcode, SUcode },
{ geDI, Tcode, DIcode, DIcode },
{ geDU, Tcode, DUcode, DUcode },
{ geSF, Tcode, SFcode, SFcode },
{ geDF, Tcode, DFcode, DFcode },
{ geXF, Tcode, XFcode, XFcode },
{ geP, Tcode, Pcode, Pcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_gt_expr[] = {
{ gtSI, Tcode, SIcode, SIcode },
{ gtSU, Tcode, SUcode, SUcode },
{ gtDI, Tcode, DIcode, DIcode },
{ gtDU, Tcode, DUcode, DUcode },
{ gtSF, Tcode, SFcode, SFcode },
{ gtDF, Tcode, DFcode, DFcode },
{ gtXF, Tcode, XFcode, XFcode },
{ gtP, Tcode, Pcode, Pcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_eq_expr[] = {
{ eqSI, Tcode, SIcode, SIcode },
{ eqDI, Tcode, DIcode, DIcode },
{ eqSF, Tcode, SFcode, SFcode },
{ eqDF, Tcode, DFcode, DFcode },
{ eqXF, Tcode, XFcode, XFcode },
{ eqP, Tcode, Pcode, Pcode },
{ -1, -1, -1, -1 },
};
struct binary_operator optab_ne_expr[] = {
{ neSI, Tcode, SIcode, SIcode },
{ neDI, Tcode, DIcode, DIcode },
{ neSF, Tcode, SFcode, SFcode },
{ neDF, Tcode, DFcode, DFcode },
{ neXF, Tcode, XFcode, XFcode },
{ neP, Tcode, Pcode, Pcode },
{ -1, -1, -1, -1 },
};
/* Unary operator tables. */
struct unary_operator optab_negate_expr[] = {
{ negSI, SIcode, SIcode },
{ negDI, DIcode, DIcode },
{ negSF, SFcode, SFcode },
{ negDF, DFcode, DFcode },
{ negXF, XFcode, XFcode },
{ -1, -1, -1 },
};
struct unary_operator optab_bit_not_expr[] = {
{ notSI, SIcode, SIcode },
{ notDI, DIcode, DIcode },
{ -1, -1, -1 },
};
struct unary_operator optab_truth_not_expr[] = {
{ notT, SIcode, SIcode },
{ -1, -1, -1 },
};
/* Increment operator tables. */
struct increment_operator optab_predecrement_expr[] = {
{ predecQI, QIcode },
{ predecQI, QUcode },
{ predecHI, HIcode },
{ predecHI, HUcode },
{ predecSI, SIcode },
{ predecSI, SUcode },
{ predecDI, DIcode },
{ predecDI, DUcode },
{ predecP, Pcode },
{ predecSF, SFcode },
{ predecDF, DFcode },
{ predecXF, XFcode },
{ -1, -1 },
};
struct increment_operator optab_preincrement_expr[] = {
{ preincQI, QIcode },
{ preincQI, QUcode },
{ preincHI, HIcode },
{ preincHI, HUcode },
{ preincSI, SIcode },
{ preincSI, SUcode },
{ preincDI, DIcode },
{ preincDI, DUcode },
{ preincP, Pcode },
{ preincSF, SFcode },
{ preincDF, DFcode },
{ preincXF, XFcode },
{ -1, -1 },
};
struct increment_operator optab_postdecrement_expr[] = {
{ postdecQI, QIcode },
{ postdecQI, QUcode },
{ postdecHI, HIcode },
{ postdecHI, HUcode },
{ postdecSI, SIcode },
{ postdecSI, SUcode },
{ postdecDI, DIcode },
{ postdecDI, DUcode },
{ postdecP, Pcode },
{ postdecSF, SFcode },
{ postdecDF, DFcode },
{ postdecXF, XFcode },
{ -1, -1 },
};
struct increment_operator optab_postincrement_expr[] = {
{ postincQI, QIcode },
{ postincQI, QUcode },
{ postincHI, HIcode },
{ postincHI, HUcode },
{ postincSI, SIcode },
{ postincSI, SUcode },
{ postincDI, DIcode },
{ postincDI, DUcode },
{ postincP, Pcode },
{ postincSF, SFcode },
{ postincDF, DFcode },
{ postincXF, XFcode },
{ -1, -1 },
};
/* Table of conversions supported by the interpreter. */
static struct conversion_info
{
enum bytecode_opcode opcode; /* here indicates the conversion needs no opcode. */
enum typecode from;
enum typecode to;
int cost; /* 1 for no-op conversions, 2 for widening conversions,
4 for int/float conversions, 8 for narrowing conversions. */
} conversion_info[] = {
{ -1, QIcode, QUcode, 1 },
{ -1, HIcode, HUcode, 1 },
{ -1, SIcode, SUcode, 1 },
{ -1, DIcode, DUcode, 1 },
{ -1, QUcode, QIcode, 1 },
{ -1, HUcode, HIcode, 1 },
{ -1, SUcode, SIcode, 1 },
{ -1, DUcode, DIcode, 1 },
{ -1, Tcode, SIcode, 1 },
{ convertQIHI, QIcode, HIcode, 2 },
{ convertQUHU, QUcode, HUcode, 2 },
{ convertQUSU, QUcode, SUcode, 2 },
{ convertHISI, HIcode, SIcode, 2 },
{ convertHUSU, HUcode, SUcode, 2 },
{ convertSIDI, SIcode, DIcode, 2 },
{ convertSUDU, SUcode, DUcode, 2 },
{ convertSFDF, SFcode, DFcode, 2 },
{ convertDFXF, DFcode, XFcode, 2 },
{ convertHIQI, HIcode, QIcode, 8 },
{ convertSIQI, SIcode, QIcode, 8 },
{ convertSIHI, SIcode, HIcode, 8 },
{ convertSUQU, SUcode, QUcode, 8 },
{ convertDISI, DIcode, SIcode, 8 },
{ convertDFSF, DFcode, SFcode, 8 },
{ convertXFDF, XFcode, DFcode, 8 },
{ convertPSI, Pcode, SIcode, 2 },
{ convertSIP, SIcode, Pcode, 2 },
{ convertSIT, SIcode, Tcode, 2 },
{ convertDIT, DIcode, Tcode, 2 },
{ convertSFT, SFcode, Tcode, 2 },
{ convertDFT, DFcode, Tcode, 2 },
{ convertXFT, XFcode, Tcode, 2 },
{ convertQISI, QIcode, SIcode, 2 },
{ convertPT, Pcode, Tcode, 2 },
{ convertSISF, SIcode, SFcode, 4 },
{ convertSIDF, SIcode, DFcode, 4 },
{ convertSIXF, SIcode, XFcode, 4 },
{ convertSUSF, SUcode, SFcode, 4 },
{ convertSUDF, SUcode, DFcode, 4 },
{ convertSUXF, SUcode, XFcode, 4 },
{ convertDISF, DIcode, SFcode, 4 },
{ convertDIDF, DIcode, DFcode, 4 },
{ convertDIXF, DIcode, XFcode, 4 },
{ convertDUSF, DUcode, SFcode, 4 },
{ convertDUDF, DUcode, DFcode, 4 },
{ convertDUXF, DUcode, XFcode, 4 },
{ convertSFSI, SFcode, SIcode, 4 },
{ convertDFSI, DFcode, SIcode, 4 },
{ convertXFSI, XFcode, SIcode, 4 },
{ convertSFSU, SFcode, SUcode, 4 },
{ convertDFSU, DFcode, SUcode, 4 },
{ convertXFSU, XFcode, SUcode, 4 },
{ convertSFDI, SFcode, DIcode, 4 },
{ convertDFDI, DFcode, DIcode, 4 },
{ convertXFDI, XFcode, DIcode, 4 },
{ convertSFDU, SFcode, DUcode, 4 },
{ convertDFDU, DFcode, DUcode, 4 },
{ convertXFDU, XFcode, DUcode, 4 },
{ convertSIQI, SIcode, QIcode, 8 },
};
#define NUM_CONVERSIONS (sizeof conversion_info / sizeof (struct conversion_info))
/* List form of a conversion recipe. */
struct conversion_list
{
enum bytecode_opcode opcode;
enum typecode to;
int cost;
struct conversion_list *prev;
};
/* Determine if it is "reasonable" to add a given conversion to
a given list of conversions. The following criteria define
"reasonable" conversion lists:
* No typecode appears more than once in the sequence (no loops).
* At most one conversion from integer to float or vice versa is present.
* Either sign extensions or zero extensions may be present, but not both.
* No widening conversions occur after a signed/unsigned conversion.
* The sequence of sizes must be strict nonincreasing or nondecreasing. */
static int
conversion_reasonable_p (conversion, list)
struct conversion_info *conversion;
struct conversion_list *list;
{
struct conversion_list *curr;
int curr_size, prev_size;
int has_int_float, has_float_int;
int has_sign_extend, has_zero_extend;
int has_signed_unsigned, has_unsigned_signed;
has_int_float = 0;
has_float_int = 0;
has_sign_extend = 0;
has_zero_extend = 0;
has_signed_unsigned = 0;
has_unsigned_signed = 0;
/* Make sure the destination typecode doesn't already appear in
the list. */
for (curr = list; curr; curr = curr->prev)
if (conversion->to == curr->to)
return 0;
/* Check for certain kinds of conversions. */
if (TYPECODE_INTEGER_P (conversion->from)
&& TYPECODE_FLOAT_P (conversion->to))
has_int_float = 1;
if (TYPECODE_FLOAT_P (conversion->from)
&& TYPECODE_INTEGER_P (conversion->to))
has_float_int = 1;
if (TYPECODE_SIGNED_P (conversion->from)
&& TYPECODE_SIGNED_P (conversion->to)
&& GET_TYPECODE_SIZE (conversion->from)
< GET_TYPECODE_SIZE (conversion->to))
has_sign_extend = 1;
if (TYPECODE_UNSIGNED_P (conversion->from)
&& TYPECODE_UNSIGNED_P (conversion->to)
&& GET_TYPECODE_SIZE (conversion->from)
< GET_TYPECODE_SIZE (conversion->to))
has_zero_extend = 1;
for (curr = list; curr && curr->prev; curr = curr->prev)
{
if (TYPECODE_INTEGER_P (curr->prev->to)
&& TYPECODE_FLOAT_P (curr->to))
has_int_float = 1;
if (TYPECODE_FLOAT_P (curr->prev->to)
&& TYPECODE_INTEGER_P (curr->to))
has_float_int = 1;
if (TYPECODE_SIGNED_P (curr->prev->to)
&& TYPECODE_SIGNED_P (curr->to)
&& GET_TYPECODE_SIZE (curr->prev->to)
< GET_TYPECODE_SIZE (curr->to))
has_sign_extend = 1;
if (TYPECODE_UNSIGNED_P (curr->prev->to)
&& TYPECODE_UNSIGNED_P (curr->to)
&& GET_TYPECODE_SIZE (curr->prev->to)
< GET_TYPECODE_SIZE (curr->to))
has_zero_extend = 1;
if (TYPECODE_SIGNED_P (curr->prev->to)
&& TYPECODE_UNSIGNED_P (curr->to))
has_signed_unsigned = 1;
if (TYPECODE_UNSIGNED_P (curr->prev->to)
&& TYPECODE_SIGNED_P (curr->to))
has_unsigned_signed = 1;
}
if (TYPECODE_INTEGER_P (conversion->from)
&& TYPECODE_INTEGER_P (conversion->to)
&& GET_TYPECODE_SIZE (conversion->to)
> GET_TYPECODE_SIZE (conversion->from)
&& (has_signed_unsigned || has_unsigned_signed))
return 0;
if (has_float_int && has_int_float || has_sign_extend && has_zero_extend)
return 0;
/* Make sure the sequence of destination typecode sizes is
strictly nondecreasing or strictly nonincreasing. */
prev_size = GET_TYPECODE_SIZE (conversion->to);
for (curr = list; curr; curr = curr->prev)
{
curr_size = GET_TYPECODE_SIZE (curr->to);
if (curr_size != prev_size)
break;
}
if (!curr)
return 1;
if (curr_size < prev_size)
for (prev_size = curr_size; curr; curr = curr->prev)
{
curr_size = GET_TYPECODE_SIZE (curr->to);
if (curr_size > prev_size)
return 0;
prev_size = curr_size;
}
else
for (prev_size = curr_size; curr; curr = curr->prev)
{
curr_size = GET_TYPECODE_SIZE (curr->to);
if (curr_size < prev_size)
return 0;
prev_size = curr_size;
}
return 1;
}
/* Exhaustively search all reasonable conversions to find one to
convert the given types. */
static struct conversion_recipe
deduce_conversion (from, to)
enum typecode from, to;
{
struct rl
{
struct conversion_list *list;
struct rl *next;
} *prev, curr, *good, *temp;
struct conversion_list *conv, *best;
int i, cost, bestcost;
struct conversion_recipe result;
struct obstack recipe_obstack;
obstack_init (&recipe_obstack);
curr.next = (struct rl *) obstack_alloc (&recipe_obstack, sizeof (struct rl));
curr.next->list =
(struct conversion_list *) obstack_alloc (&recipe_obstack,
sizeof (struct conversion_list));
curr.next->list->opcode = -1;
curr.next->list->to = from;
curr.next->list->cost = 0;
curr.next->list->prev = 0;
curr.next->next = 0;
good = 0;
while (curr.next)
{
/* Remove successful conversions from further consideration. */
for (prev = &curr; prev; prev = prev->next)
if (prev->next && prev->next->list->to == to)
{
temp = prev->next->next;
prev->next->next = good;
good = prev->next;
prev->next = temp;
}
/* Go through each of the pending conversion chains, trying
all possible candidate conversions on them. */
for (prev = curr.next, curr.next = 0; prev; prev = prev->next)
for (i = 0; i < NUM_CONVERSIONS; ++i)
if (conversion_info[i].from == prev->list->to
&& conversion_reasonable_p (&conversion_info[i], prev->list))
{
temp = (struct rl *) obstack_alloc (&recipe_obstack,
sizeof (struct rl));
temp->list = (struct conversion_list *)
obstack_alloc (&recipe_obstack,
sizeof (struct conversion_list));
temp->list->opcode = conversion_info[i].opcode;
temp->list->to = conversion_info[i].to;
temp->list->cost = conversion_info[i].cost;
temp->list->prev = prev->list;
temp->next = curr.next;
curr.next = temp;
}
}
bestcost = BIG_ARBITRARY_NUMBER;
best = 0;
for (temp = good; temp; temp = temp->next)
{
for (conv = temp->list, cost = 0; conv; conv = conv->prev)
cost += conv->cost;
if (cost < bestcost)
{
bestcost = cost;
best = temp->list;
}
}
if (!best)
abort ();
for (i = 0, conv = best; conv; conv = conv->prev)
if (conv->opcode != -1)
++i;
result.opcodes = (unsigned char *) xmalloc (i);
result.nopcodes = i;
for (conv = best; conv; conv = conv->prev)
if (conv->opcode != -1)
result.opcodes[--i] = conv->opcode;
result.cost = bestcost;
obstack_free (&recipe_obstack, 0);
return result;
}
#define DEDUCE_CONVERSION(FROM, TO) \
(conversion_recipe[(int) FROM][(int) TO].opcodes ? 0 \
: (conversion_recipe[(int) FROM][(int) TO] \
= deduce_conversion (FROM, TO), 0))
/* Emit a conversion between the given scalar types. */
void
emit_typecode_conversion (from, to)
enum typecode from, to;
{
int i;
DEDUCE_CONVERSION (from, to);
for (i = 0; i < conversion_recipe[(int) from][(int) to].nopcodes; ++i)
bc_emit_instruction (conversion_recipe[(int) from][(int) to].opcodes[i]);
}
/* Initialize mode_to_code_map[] */
void
bc_init_mode_to_code_map ()
{
int mode;
for (mode = 0; mode < MAX_MACHINE_MODE + 1; mode++)
{
signed_mode_to_code_map[mode] =
unsigned_mode_to_code_map[mode] =
LAST_AND_UNUSED_TYPECODE;
}
#define DEF_MODEMAP(SYM, CODE, UCODE, CONST, LOAD, STORE) \
{ signed_mode_to_code_map[(int) SYM] = CODE; \
unsigned_mode_to_code_map[(int) SYM] = UCODE; }
#include "modemap.def"
#undef DEF_MODEMAP
/* Initialize opcode maps for const, load, and store */
bc_init_mode_to_opcode_maps ();
}
/* Given a machine mode return the preferred typecode. */
enum typecode
preferred_typecode (mode, unsignedp)
enum machine_mode mode;
int unsignedp;
{
enum typecode code = (unsignedp
? unsigned_mode_to_code_map
: signed_mode_to_code_map) [MIN ((int) mode,
(int) MAX_MACHINE_MODE)];
if (code == LAST_AND_UNUSED_TYPECODE)
abort ();
return code;
}
/* Expand a conversion between the given types. */
void
bc_expand_conversion (from, to)
tree from, to;
{
enum typecode fcode, tcode;
fcode = preferred_typecode (TYPE_MODE (from), TREE_UNSIGNED (from));
tcode = preferred_typecode (TYPE_MODE (to), TREE_UNSIGNED (to));
emit_typecode_conversion (fcode, tcode);
}
/* Expand a conversion of the given type to a truth value. */
void
bc_expand_truth_conversion (from)
tree from;
{
enum typecode fcode;
fcode = preferred_typecode (TYPE_MODE (from), TREE_UNSIGNED (from));
emit_typecode_conversion (fcode, Tcode);
}
/* Emit an appropriate binary operation. */
void
bc_expand_binary_operation (optab, resulttype, arg0, arg1)
struct binary_operator optab[];
tree resulttype, arg0, arg1;
{
int i, besti, cost, bestcost;
enum typecode resultcode, arg0code, arg1code;
resultcode = preferred_typecode (TYPE_MODE (resulttype), TREE_UNSIGNED (resulttype));
arg0code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg0)), TREE_UNSIGNED (resulttype));
arg1code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg1)), TREE_UNSIGNED (resulttype));
besti = -1;
bestcost = BIG_ARBITRARY_NUMBER;
for (i = 0; optab[i].opcode != -1; ++i)
{
cost = 0;
DEDUCE_CONVERSION (arg0code, optab[i].arg0);
cost += conversion_recipe[(int) arg0code][(int) optab[i].arg0].cost;
DEDUCE_CONVERSION (arg1code, optab[i].arg1);
cost += conversion_recipe[(int) arg1code][(int) optab[i].arg1].cost;
if (cost < bestcost)
{
besti = i;
bestcost = cost;
}
}
if (besti == -1)
abort ();
expand_expr (arg1, 0, VOIDmode, 0);
emit_typecode_conversion (arg1code, optab[besti].arg1);
expand_expr (arg0, 0, VOIDmode, 0);
emit_typecode_conversion (arg0code, optab[besti].arg0);
bc_emit_instruction (optab[besti].opcode);
emit_typecode_conversion (optab[besti].result, resultcode);
}
/* Emit an appropriate unary operation. */
void
bc_expand_unary_operation (optab, resulttype, arg0)
struct unary_operator optab[];
tree resulttype, arg0;
{
int i, besti, cost, bestcost;
enum typecode resultcode, arg0code;
resultcode = preferred_typecode (TYPE_MODE (resulttype), TREE_UNSIGNED (resulttype));
arg0code = preferred_typecode (TYPE_MODE (TREE_TYPE (arg0)), TREE_UNSIGNED (TREE_TYPE (arg0)));
besti = -1;
bestcost = BIG_ARBITRARY_NUMBER;
for (i = 0; optab[i].opcode != -1; ++i)
{
DEDUCE_CONVERSION (arg0code, optab[i].arg0);
cost = conversion_recipe[(int) arg0code][(int) optab[i].arg0].cost;
if (cost < bestcost)
{
besti = i;
bestcost = cost;
}
}
if (besti == -1)
abort ();
expand_expr (arg0, 0, VOIDmode, 0);
emit_typecode_conversion (arg0code, optab[besti].arg0);
bc_emit_instruction (optab[besti].opcode);
emit_typecode_conversion (optab[besti].result, resultcode);
}
/* Emit an appropriate increment. */
void
bc_expand_increment (optab, type)
struct increment_operator optab[];
tree type;
{
enum typecode code;
int i;
code = preferred_typecode (TYPE_MODE (type), TREE_UNSIGNED (type));
for (i = 0; (int) optab[i].opcode >= 0; ++i)
if (code == optab[i].arg)
{
bc_emit_instruction (optab[i].opcode);
return;
}
abort ();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,762 @@
/* Save and restore call-clobbered registers which are live across a call.
Copyright (C) 1989, 1992, 1994 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include "rtl.h"
#include "insn-config.h"
#include "flags.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "recog.h"
#include "basic-block.h"
#include "reload.h"
#include "expr.h"
#ifndef MAX_MOVE_MAX
#define MAX_MOVE_MAX MOVE_MAX
#endif
#ifndef MAX_UNITS_PER_WORD
#define MAX_UNITS_PER_WORD UNITS_PER_WORD
#endif
/* Modes for each hard register that we can save. The smallest mode is wide
enough to save the entire contents of the register. When saving the
register because it is live we first try to save in multi-register modes.
If that is not possible the save is done one register at a time. */
static enum machine_mode
regno_save_mode[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
/* For each hard register, a place on the stack where it can be saved,
if needed. */
static rtx
regno_save_mem[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
/* We will only make a register eligible for caller-save if it can be
saved in its widest mode with a simple SET insn as long as the memory
address is valid. We record the INSN_CODE is those insns here since
when we emit them, the addresses might not be valid, so they might not
be recognized. */
static enum insn_code
reg_save_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
static enum insn_code
reg_restore_code[FIRST_PSEUDO_REGISTER][MAX_MOVE_MAX / MAX_UNITS_PER_WORD + 1];
/* Set of hard regs currently live (during scan of all insns). */
static HARD_REG_SET hard_regs_live;
/* Set of hard regs currently residing in save area (during insn scan). */
static HARD_REG_SET hard_regs_saved;
/* Set of hard regs which need to be restored before referenced. */
static HARD_REG_SET hard_regs_need_restore;
/* Number of registers currently in hard_regs_saved. */
int n_regs_saved;
static void set_reg_live PROTO((rtx, rtx));
static void clear_reg_live PROTO((rtx));
static void restore_referenced_regs PROTO((rtx, rtx, enum machine_mode));
static int insert_save_restore PROTO((rtx, int, int,
enum machine_mode, int));
/* Initialize for caller-save.
Look at all the hard registers that are used by a call and for which
regclass.c has not already excluded from being used across a call.
Ensure that we can find a mode to save the register and that there is a
simple insn to save and restore the register. This latter check avoids
problems that would occur if we tried to save the MQ register of some
machines directly into memory. */
void
init_caller_save ()
{
char *first_obj = (char *) oballoc (0);
rtx addr_reg;
int offset;
rtx address;
int i, j;
/* First find all the registers that we need to deal with and all
the modes that they can have. If we can't find a mode to use,
we can't have the register live over calls. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if (call_used_regs[i] && ! call_fixed_regs[i])
{
for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
{
regno_save_mode[i][j] = choose_hard_reg_mode (i, j);
if (regno_save_mode[i][j] == VOIDmode && j == 1)
{
call_fixed_regs[i] = 1;
SET_HARD_REG_BIT (call_fixed_reg_set, i);
}
}
}
else
regno_save_mode[i][1] = VOIDmode;
}
/* The following code tries to approximate the conditions under which
we can easily save and restore a register without scratch registers or
other complexities. It will usually work, except under conditions where
the validity of an insn operand is dependent on the address offset.
No such cases are currently known.
We first find a typical offset from some BASE_REG_CLASS register.
This address is chosen by finding the first register in the class
and by finding the smallest power of two that is a valid offset from
that register in every mode we will use to save registers. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (TEST_HARD_REG_BIT (reg_class_contents[(int) BASE_REG_CLASS], i))
break;
if (i == FIRST_PSEUDO_REGISTER)
abort ();
addr_reg = gen_rtx (REG, Pmode, i);
for (offset = 1 << (HOST_BITS_PER_INT / 2); offset; offset >>= 1)
{
address = gen_rtx (PLUS, Pmode, addr_reg, GEN_INT (offset));
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (regno_save_mode[i][1] != VOIDmode
&& ! strict_memory_address_p (regno_save_mode[i][1], address))
break;
if (i == FIRST_PSEUDO_REGISTER)
break;
}
/* If we didn't find a valid address, we must use register indirect. */
if (offset == 0)
address = addr_reg;
/* Next we try to form an insn to save and restore the register. We
see if such an insn is recognized and meets its constraints. */
start_sequence ();
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
if (regno_save_mode[i][j] != VOIDmode)
{
rtx mem = gen_rtx (MEM, regno_save_mode[i][j], address);
rtx reg = gen_rtx (REG, regno_save_mode[i][j], i);
rtx savepat = gen_rtx (SET, VOIDmode, mem, reg);
rtx restpat = gen_rtx (SET, VOIDmode, reg, mem);
rtx saveinsn = emit_insn (savepat);
rtx restinsn = emit_insn (restpat);
int ok;
reg_save_code[i][j] = recog_memoized (saveinsn);
reg_restore_code[i][j] = recog_memoized (restinsn);
/* Now extract both insns and see if we can meet their constraints. */
ok = (reg_save_code[i][j] != -1 && reg_restore_code[i][j] != -1);
if (ok)
{
insn_extract (saveinsn);
ok = constrain_operands (reg_save_code[i][j], 1);
insn_extract (restinsn);
ok &= constrain_operands (reg_restore_code[i][j], 1);
}
if (! ok)
{
regno_save_mode[i][j] = VOIDmode;
if (j == 1)
{
call_fixed_regs[i] = 1;
SET_HARD_REG_BIT (call_fixed_reg_set, i);
}
}
}
end_sequence ();
obfree (first_obj);
}
/* Initialize save areas by showing that we haven't allocated any yet. */
void
init_save_areas ()
{
int i, j;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
regno_save_mem[i][j] = 0;
}
/* Allocate save areas for any hard registers that might need saving.
We take a conservative approach here and look for call-clobbered hard
registers that are assigned to pseudos that cross calls. This may
overestimate slightly (especially if some of these registers are later
used as spill registers), but it should not be significant.
Then perform register elimination in the addresses of the save area
locations; return 1 if all eliminated addresses are strictly valid.
We assume that our caller has set up the elimination table to the
worst (largest) possible offsets.
Set *PCHANGED to 1 if we had to allocate some memory for the save area.
Future work:
In the fallback case we should iterate backwards across all possible
modes for the save, choosing the largest available one instead of
falling back to the smallest mode immediately. (eg TF -> DF -> SF).
We do not try to use "move multiple" instructions that exist
on some machines (such as the 68k moveml). It could be a win to try
and use them when possible. The hard part is doing it in a way that is
machine independent since they might be saving non-consecutive
registers. (imagine caller-saving d0,d1,a0,a1 on the 68k) */
int
setup_save_areas (pchanged)
int *pchanged;
{
int i, j, k;
HARD_REG_SET hard_regs_used;
int ok = 1;
/* Allocate space in the save area for the largest multi-register
pseudos first, then work backwards to single register
pseudos. */
/* Find and record all call-used hard-registers in this function. */
CLEAR_HARD_REG_SET (hard_regs_used);
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
if (reg_renumber[i] >= 0 && reg_n_calls_crossed[i] > 0)
{
int regno = reg_renumber[i];
int endregno
= regno + HARD_REGNO_NREGS (regno, GET_MODE (regno_reg_rtx[i]));
int nregs = endregno - regno;
for (j = 0; j < nregs; j++)
{
if (call_used_regs[regno+j])
SET_HARD_REG_BIT (hard_regs_used, regno+j);
}
}
/* Now run through all the call-used hard-registers and allocate
space for them in the caller-save area. Try to allocate space
in a manner which allows multi-register saves/restores to be done. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
for (j = MOVE_MAX / UNITS_PER_WORD; j > 0; j--)
{
int ok = 1;
int do_save;
/* If no mode exists for this size, try another. Also break out
if we have already saved this hard register. */
if (regno_save_mode[i][j] == VOIDmode || regno_save_mem[i][1] != 0)
continue;
/* See if any register in this group has been saved. */
do_save = 1;
for (k = 0; k < j; k++)
if (regno_save_mem[i + k][1])
{
do_save = 0;
break;
}
if (! do_save)
continue;
for (k = 0; k < j; k++)
{
int regno = i + k;
ok &= (TEST_HARD_REG_BIT (hard_regs_used, regno) != 0);
}
/* We have found an acceptable mode to store in. */
if (ok)
{
regno_save_mem[i][j]
= assign_stack_local (regno_save_mode[i][j],
GET_MODE_SIZE (regno_save_mode[i][j]), 0);
/* Setup single word save area just in case... */
for (k = 0; k < j; k++)
{
/* This should not depend on WORDS_BIG_ENDIAN.
The order of words in regs is the same as in memory. */
rtx temp = gen_rtx (MEM, regno_save_mode[i+k][1],
XEXP (regno_save_mem[i][j], 0));
regno_save_mem[i+k][1]
= adj_offsettable_operand (temp, k * UNITS_PER_WORD);
}
*pchanged = 1;
}
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
if (regno_save_mem[i][j] != 0)
ok &= strict_memory_address_p (GET_MODE (regno_save_mem[i][j]),
XEXP (eliminate_regs (regno_save_mem[i][j], 0, NULL_RTX), 0));
return ok;
}
/* Find the places where hard regs are live across calls and save them.
INSN_MODE is the mode to assign to any insns that we add. This is used
by reload to determine whether or not reloads or register eliminations
need be done on these insns. */
void
save_call_clobbered_regs (insn_mode)
enum machine_mode insn_mode;
{
rtx insn;
int b;
for (b = 0; b < n_basic_blocks; b++)
{
regset regs_live = basic_block_live_at_start[b];
rtx prev_block_last = PREV_INSN (basic_block_head[b]);
REGSET_ELT_TYPE bit;
int offset, i, j;
int regno;
/* Compute hard regs live at start of block -- this is the
real hard regs marked live, plus live pseudo regs that
have been renumbered to hard regs. No registers have yet been
saved because we restore all of them before the end of the basic
block. */
#ifdef HARD_REG_SET
hard_regs_live = *regs_live;
#else
COPY_HARD_REG_SET (hard_regs_live, regs_live);
#endif
CLEAR_HARD_REG_SET (hard_regs_saved);
CLEAR_HARD_REG_SET (hard_regs_need_restore);
n_regs_saved = 0;
for (offset = 0, i = 0; offset < regset_size; offset++)
{
if (regs_live[offset] == 0)
i += REGSET_ELT_BITS;
else
for (bit = 1; bit && i < max_regno; bit <<= 1, i++)
if ((regs_live[offset] & bit)
&& (regno = reg_renumber[i]) >= 0)
for (j = regno;
j < regno + HARD_REGNO_NREGS (regno,
PSEUDO_REGNO_MODE (i));
j++)
SET_HARD_REG_BIT (hard_regs_live, j);
}
/* Now scan the insns in the block, keeping track of what hard
regs are live as we go. When we see a call, save the live
call-clobbered hard regs. */
for (insn = basic_block_head[b]; ; insn = NEXT_INSN (insn))
{
RTX_CODE code = GET_CODE (insn);
if (GET_RTX_CLASS (code) == 'i')
{
rtx link;
/* If some registers have been saved, see if INSN references
any of them. We must restore them before the insn if so. */
if (n_regs_saved)
restore_referenced_regs (PATTERN (insn), insn, insn_mode);
/* NB: the normal procedure is to first enliven any
registers set by insn, then deaden any registers that
had their last use at insn. This is incorrect now,
since multiple pseudos may have been mapped to the
same hard reg, and the death notes are ambiguous. So
it must be done in the other, safe, order. */
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_DEAD)
clear_reg_live (XEXP (link, 0));
/* When we reach a call, we need to save all registers that are
live, call-used, not fixed, and not already saved. We must
test at this point because registers that die in a CALL_INSN
are not live across the call and likewise for registers that
are born in the CALL_INSN.
If registers are filled with parameters for this function,
and some of these are also being set by this function, then
they will not appear to die (no REG_DEAD note for them),
to check if in fact they do, collect the set registers in
hard_regs_live first. */
if (code == CALL_INSN)
{
HARD_REG_SET this_call_sets;
{
HARD_REG_SET old_hard_regs_live;
/* Save the hard_regs_live information. */
COPY_HARD_REG_SET (old_hard_regs_live, hard_regs_live);
/* Now calculate hard_regs_live for this CALL_INSN
only. */
CLEAR_HARD_REG_SET (hard_regs_live);
note_stores (PATTERN (insn), set_reg_live);
COPY_HARD_REG_SET (this_call_sets, hard_regs_live);
/* Restore the hard_regs_live information. */
COPY_HARD_REG_SET (hard_regs_live, old_hard_regs_live);
}
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (call_used_regs[regno] && ! call_fixed_regs[regno]
&& TEST_HARD_REG_BIT (hard_regs_live, regno)
/* It must not be set by this instruction. */
&& ! TEST_HARD_REG_BIT (this_call_sets, regno)
&& ! TEST_HARD_REG_BIT (hard_regs_saved, regno))
regno += insert_save_restore (insn, 1, regno,
insn_mode, 0);
/* Put the information for this CALL_INSN on top of what
we already had. */
IOR_HARD_REG_SET (hard_regs_live, this_call_sets);
COPY_HARD_REG_SET (hard_regs_need_restore, hard_regs_saved);
/* Must recompute n_regs_saved. */
n_regs_saved = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (TEST_HARD_REG_BIT (hard_regs_saved, regno))
n_regs_saved++;
}
else
note_stores (PATTERN (insn), set_reg_live);
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == REG_UNUSED)
clear_reg_live (XEXP (link, 0));
}
if (insn == basic_block_end[b])
break;
}
/* At the end of the basic block, we must restore any registers that
remain saved. If the last insn in the block is a JUMP_INSN, put
the restore before the insn, otherwise, put it after the insn. */
if (n_regs_saved)
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (TEST_HARD_REG_BIT (hard_regs_need_restore, regno))
regno += insert_save_restore ((GET_CODE (insn) == JUMP_INSN
? insn : NEXT_INSN (insn)), 0,
regno, insn_mode, MOVE_MAX / UNITS_PER_WORD);
/* If we added any insns at the start of the block, update the start
of the block to point at those insns. */
basic_block_head[b] = NEXT_INSN (prev_block_last);
}
}
/* Here from note_stores when an insn stores a value in a register.
Set the proper bit or bits in hard_regs_live. All pseudos that have
been assigned hard regs have had their register number changed already,
so we can ignore pseudos. */
static void
set_reg_live (reg, setter)
rtx reg, setter;
{
register int regno, endregno, i;
enum machine_mode mode = GET_MODE (reg);
int word = 0;
if (GET_CODE (reg) == SUBREG)
{
word = SUBREG_WORD (reg);
reg = SUBREG_REG (reg);
}
if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
return;
regno = REGNO (reg) + word;
endregno = regno + HARD_REGNO_NREGS (regno, mode);
for (i = regno; i < endregno; i++)
{
SET_HARD_REG_BIT (hard_regs_live, i);
CLEAR_HARD_REG_BIT (hard_regs_saved, i);
CLEAR_HARD_REG_BIT (hard_regs_need_restore, i);
}
}
/* Here when a REG_DEAD note records the last use of a reg. Clear
the appropriate bit or bits in hard_regs_live. Again we can ignore
pseudos. */
static void
clear_reg_live (reg)
rtx reg;
{
register int regno, endregno, i;
if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
return;
regno = REGNO (reg);
endregno= regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
for (i = regno; i < endregno; i++)
{
CLEAR_HARD_REG_BIT (hard_regs_live, i);
CLEAR_HARD_REG_BIT (hard_regs_need_restore, i);
CLEAR_HARD_REG_BIT (hard_regs_saved, i);
}
}
/* If any register currently residing in the save area is referenced in X,
which is part of INSN, emit code to restore the register in front of INSN.
INSN_MODE is the mode to assign to any insns that we add. */
static void
restore_referenced_regs (x, insn, insn_mode)
rtx x;
rtx insn;
enum machine_mode insn_mode;
{
enum rtx_code code = GET_CODE (x);
char *fmt;
int i, j;
if (code == CLOBBER)
return;
if (code == REG)
{
int regno = REGNO (x);
/* If this is a pseudo, scan its memory location, since it might
involve the use of another register, which might be saved. */
if (regno >= FIRST_PSEUDO_REGISTER
&& reg_equiv_mem[regno] != 0)
restore_referenced_regs (XEXP (reg_equiv_mem[regno], 0),
insn, insn_mode);
else if (regno >= FIRST_PSEUDO_REGISTER
&& reg_equiv_address[regno] != 0)
restore_referenced_regs (reg_equiv_address[regno],
insn, insn_mode);
/* Otherwise if this is a hard register, restore any piece of it that
is currently saved. */
else if (regno < FIRST_PSEUDO_REGISTER)
{
int numregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
/* Save at most SAVEREGS at a time. This can not be larger than
MOVE_MAX, because that causes insert_save_restore to fail. */
int saveregs = MIN (numregs, MOVE_MAX / UNITS_PER_WORD);
int endregno = regno + numregs;
for (i = regno; i < endregno; i++)
if (TEST_HARD_REG_BIT (hard_regs_need_restore, i))
i += insert_save_restore (insn, 0, i, insn_mode, saveregs);
}
return;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
restore_referenced_regs (XEXP (x, i), insn, insn_mode);
else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
restore_referenced_regs (XVECEXP (x, i, j), insn, insn_mode);
}
}
/* Insert a sequence of insns to save or restore, SAVE_P says which,
REGNO. Place these insns in front of INSN. INSN_MODE is the mode
to assign to these insns. MAXRESTORE is the maximum number of registers
which should be restored during this call (when SAVE_P == 0). It should
never be less than 1 since we only work with entire registers.
Note that we have verified in init_caller_save that we can do this
with a simple SET, so use it. Set INSN_CODE to what we save there
since the address might not be valid so the insn might not be recognized.
These insns will be reloaded and have register elimination done by
find_reload, so we need not worry about that here.
Return the extra number of registers saved. */
static int
insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
rtx insn;
int save_p;
int regno;
enum machine_mode insn_mode;
int maxrestore;
{
rtx pat;
enum insn_code code;
int i, numregs;
/* A common failure mode if register status is not correct in the RTL
is for this routine to be called with a REGNO we didn't expect to
save. That will cause us to write an insn with a (nil) SET_DEST
or SET_SRC. Instead of doing so and causing a crash later, check
for this common case and abort here instead. This will remove one
step in debugging such problems. */
if (regno_save_mem[regno][1] == 0)
abort ();
#ifdef HAVE_cc0
/* If INSN references CC0, put our insns in front of the insn that sets
CC0. This is always safe, since the only way we could be passed an
insn that references CC0 is for a restore, and doing a restore earlier
isn't a problem. We do, however, assume here that CALL_INSNs don't
reference CC0. Guard against non-INSN's like CODE_LABEL. */
if ((GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
&& reg_referenced_p (cc0_rtx, PATTERN (insn)))
insn = prev_nonnote_insn (insn);
#endif
/* Get the pattern to emit and update our status. */
if (save_p)
{
int i, j, k;
int ok;
/* See if we can save several registers with a single instruction.
Work backwards to the single register case. */
for (i = MOVE_MAX / UNITS_PER_WORD; i > 0; i--)
{
ok = 1;
if (regno_save_mem[regno][i] != 0)
for (j = 0; j < i; j++)
{
if (! call_used_regs[regno + j] || call_fixed_regs[regno + j]
|| ! TEST_HARD_REG_BIT (hard_regs_live, regno + j)
|| TEST_HARD_REG_BIT (hard_regs_saved, regno + j))
ok = 0;
}
else
continue;
/* Must do this one save at a time */
if (! ok)
continue;
pat = gen_rtx (SET, VOIDmode, regno_save_mem[regno][i],
gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]), regno));
code = reg_save_code[regno][i];
/* Set hard_regs_saved for all the registers we saved. */
for (k = 0; k < i; k++)
{
SET_HARD_REG_BIT (hard_regs_saved, regno + k);
SET_HARD_REG_BIT (hard_regs_need_restore, regno + k);
n_regs_saved++;
}
numregs = i;
break;
}
}
else
{
int i, j, k;
int ok;
/* See if we can restore `maxrestore' registers at once. Work
backwards to the single register case. */
for (i = maxrestore; i > 0; i--)
{
ok = 1;
if (regno_save_mem[regno][i])
for (j = 0; j < i; j++)
{
if (! TEST_HARD_REG_BIT (hard_regs_need_restore, regno + j))
ok = 0;
}
else
continue;
/* Must do this one restore at a time */
if (! ok)
continue;
pat = gen_rtx (SET, VOIDmode,
gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]),
regno),
regno_save_mem[regno][i]);
code = reg_restore_code[regno][i];
/* Clear status for all registers we restored. */
for (k = 0; k < i; k++)
{
CLEAR_HARD_REG_BIT (hard_regs_need_restore, regno + k);
n_regs_saved--;
}
numregs = i;
break;
}
}
/* Emit the insn and set the code and mode. */
insn = emit_insn_before (pat, insn);
PUT_MODE (insn, insn_mode);
INSN_CODE (insn) = code;
/* Tell our callers how many extra registers we saved/restored */
return numregs - 1;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,460 @@
/* Utility routines for data type conversion for GNU C.
Copyright (C) 1987, 1988, 1991, 1992, 1994 Free Software Foundation, Inc.
This file is part of GNU C.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* These routines are somewhat language-independent utility function
intended to be called by the language-specific convert () functions. */
#include "config.h"
#include "tree.h"
#include "flags.h"
#include "convert.h"
/* Convert EXPR to some pointer type TYPE.
EXPR must be pointer, integer, enumeral, or literal zero;
in other cases error is called. */
tree
convert_to_pointer (type, expr)
tree type, expr;
{
register tree intype = TREE_TYPE (expr);
register enum tree_code form = TREE_CODE (intype);
if (integer_zerop (expr))
{
if (type == TREE_TYPE (null_pointer_node))
return null_pointer_node;
expr = build_int_2 (0, 0);
TREE_TYPE (expr) = type;
return expr;
}
if (form == POINTER_TYPE)
return build1 (NOP_EXPR, type, expr);
if (form == INTEGER_TYPE || form == ENUMERAL_TYPE)
{
if (type_precision (intype) == POINTER_SIZE)
return build1 (CONVERT_EXPR, type, expr);
expr = convert (type_for_size (POINTER_SIZE, 0), expr);
/* Modes may be different but sizes should be the same. */
if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr)))
!= GET_MODE_SIZE (TYPE_MODE (type)))
/* There is supposed to be some integral type
that is the same width as a pointer. */
abort ();
return convert_to_pointer (type, expr);
}
error ("cannot convert to a pointer type");
return null_pointer_node;
}
/* Convert EXPR to some floating-point type TYPE.
EXPR must be float, integer, or enumeral;
in other cases error is called. */
tree
convert_to_real (type, expr)
tree type, expr;
{
register enum tree_code form = TREE_CODE (TREE_TYPE (expr));
if (form == REAL_TYPE)
return build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
type, expr);
if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
return build1 (FLOAT_EXPR, type, expr);
if (form == COMPLEX_TYPE)
return convert (type, fold (build1 (REALPART_EXPR,
TREE_TYPE (TREE_TYPE (expr)), expr)));
if (form == POINTER_TYPE)
error ("pointer value used where a floating point value was expected");
else
error ("aggregate value used where a float was expected");
{
register tree tem = make_node (REAL_CST);
TREE_TYPE (tem) = type;
TREE_REAL_CST (tem) = REAL_VALUE_ATOF ("0.0", TYPE_MODE (type));
return tem;
}
}
/* Convert EXPR to some integer (or enum) type TYPE.
EXPR must be pointer, integer, discrete (enum, char, or bool), or float;
in other cases error is called.
The result of this is always supposed to be a newly created tree node
not in use in any existing structure. */
tree
convert_to_integer (type, expr)
tree type, expr;
{
register tree intype = TREE_TYPE (expr);
register enum tree_code form = TREE_CODE (intype);
if (form == POINTER_TYPE)
{
if (integer_zerop (expr))
expr = integer_zero_node;
else
expr = fold (build1 (CONVERT_EXPR,
type_for_size (POINTER_SIZE, 0), expr));
intype = TREE_TYPE (expr);
form = TREE_CODE (intype);
if (intype == type)
return expr;
}
if (form == INTEGER_TYPE || form == ENUMERAL_TYPE
|| form == BOOLEAN_TYPE || form == CHAR_TYPE)
{
register unsigned outprec = TYPE_PRECISION (type);
register unsigned inprec = TYPE_PRECISION (intype);
register enum tree_code ex_form = TREE_CODE (expr);
/* If we are widening the type, put in an explicit conversion.
Similarly if we are not changing the width. However, if this is
a logical operation that just returns 0 or 1, we can change the
type of the expression. For logical operations, we must
also change the types of the operands to maintain type
correctness. */
if (TREE_CODE_CLASS (ex_form) == '<')
{
TREE_TYPE (expr) = type;
return expr;
}
else if (ex_form == TRUTH_AND_EXPR || ex_form == TRUTH_ANDIF_EXPR
|| ex_form == TRUTH_OR_EXPR || ex_form == TRUTH_ORIF_EXPR
|| ex_form == TRUTH_XOR_EXPR)
{
TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0));
TREE_OPERAND (expr, 1) = convert (type, TREE_OPERAND (expr, 1));
TREE_TYPE (expr) = type;
return expr;
}
else if (ex_form == TRUTH_NOT_EXPR)
{
TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0));
TREE_TYPE (expr) = type;
return expr;
}
else if (outprec >= inprec)
return build1 (NOP_EXPR, type, expr);
/* Here detect when we can distribute the truncation down past some
arithmetic. For example, if adding two longs and converting to an
int, we can equally well convert both to ints and then add.
For the operations handled here, such truncation distribution
is always safe.
It is desirable in these cases:
1) when truncating down to full-word from a larger size
2) when truncating takes no work.
3) when at least one operand of the arithmetic has been extended
(as by C's default conversions). In this case we need two conversions
if we do the arithmetic as already requested, so we might as well
truncate both and then combine. Perhaps that way we need only one.
Note that in general we cannot do the arithmetic in a type
shorter than the desired result of conversion, even if the operands
are both extended from a shorter type, because they might overflow
if combined in that type. The exceptions to this--the times when
two narrow values can be combined in their narrow type even to
make a wider result--are handled by "shorten" in build_binary_op. */
switch (ex_form)
{
case RSHIFT_EXPR:
/* We can pass truncation down through right shifting
when the shift count is a nonpositive constant. */
if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
&& tree_int_cst_lt (TREE_OPERAND (expr, 1),
convert (TREE_TYPE (TREE_OPERAND (expr, 1)),
integer_one_node)))
goto trunc1;
break;
case LSHIFT_EXPR:
/* We can pass truncation down through left shifting
when the shift count is a nonnegative constant. */
if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
&& tree_int_cst_sgn (TREE_OPERAND (expr, 1)) >= 0
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
{
/* If shift count is less than the width of the truncated type,
really shift. */
if (tree_int_cst_lt (TREE_OPERAND (expr, 1), TYPE_SIZE (type)))
/* In this case, shifting is like multiplication. */
goto trunc1;
else
{
/* If it is >= that width, result is zero.
Handling this with trunc1 would give the wrong result:
(int) ((long long) a << 32) is well defined (as 0)
but (int) a << 32 is undefined and would get a
warning. */
tree t = convert_to_integer (type, integer_zero_node);
/* If the original expression had side-effects, we must
preserve it. */
if (TREE_SIDE_EFFECTS (expr))
return build (COMPOUND_EXPR, type, expr, t);
else
return t;
}
}
break;
case MAX_EXPR:
case MIN_EXPR:
case MULT_EXPR:
{
tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type);
tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
/* Don't distribute unless the output precision is at least as big
as the actual inputs. Otherwise, the comparison of the
truncated values will be wrong. */
if (outprec >= TYPE_PRECISION (TREE_TYPE (arg0))
&& outprec >= TYPE_PRECISION (TREE_TYPE (arg1))
/* If signedness of arg0 and arg1 don't match,
we can't necessarily find a type to compare them in. */
&& (TREE_UNSIGNED (TREE_TYPE (arg0))
== TREE_UNSIGNED (TREE_TYPE (arg1))))
goto trunc1;
break;
}
case PLUS_EXPR:
case MINUS_EXPR:
case BIT_AND_EXPR:
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
case BIT_ANDTC_EXPR:
trunc1:
{
tree arg0 = get_unwidened (TREE_OPERAND (expr, 0), type);
tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
if (outprec >= BITS_PER_WORD
|| TRULY_NOOP_TRUNCATION (outprec, inprec)
|| inprec > TYPE_PRECISION (TREE_TYPE (arg0))
|| inprec > TYPE_PRECISION (TREE_TYPE (arg1)))
{
/* Do the arithmetic in type TYPEX,
then convert result to TYPE. */
register tree typex = type;
/* Can't do arithmetic in enumeral types
so use an integer type that will hold the values. */
if (TREE_CODE (typex) == ENUMERAL_TYPE)
typex = type_for_size (TYPE_PRECISION (typex),
TREE_UNSIGNED (typex));
/* But now perhaps TYPEX is as wide as INPREC.
In that case, do nothing special here.
(Otherwise would recurse infinitely in convert. */
if (TYPE_PRECISION (typex) != inprec)
{
/* Don't do unsigned arithmetic where signed was wanted,
or vice versa.
Exception: if either of the original operands were
unsigned then can safely do the work as unsigned.
And we may need to do it as unsigned
if we truncate to the original size. */
typex = ((TREE_UNSIGNED (TREE_TYPE (expr))
|| TREE_UNSIGNED (TREE_TYPE (arg0))
|| TREE_UNSIGNED (TREE_TYPE (arg1)))
? unsigned_type (typex) : signed_type (typex));
return convert (type,
fold (build (ex_form, typex,
convert (typex, arg0),
convert (typex, arg1),
0)));
}
}
}
break;
case NEGATE_EXPR:
case BIT_NOT_EXPR:
/* This is not correct for ABS_EXPR,
since we must test the sign before truncation. */
{
register tree typex = type;
/* Can't do arithmetic in enumeral types
so use an integer type that will hold the values. */
if (TREE_CODE (typex) == ENUMERAL_TYPE)
typex = type_for_size (TYPE_PRECISION (typex),
TREE_UNSIGNED (typex));
/* But now perhaps TYPEX is as wide as INPREC.
In that case, do nothing special here.
(Otherwise would recurse infinitely in convert. */
if (TYPE_PRECISION (typex) != inprec)
{
/* Don't do unsigned arithmetic where signed was wanted,
or vice versa. */
typex = (TREE_UNSIGNED (TREE_TYPE (expr))
? unsigned_type (typex) : signed_type (typex));
return convert (type,
fold (build1 (ex_form, typex,
convert (typex,
TREE_OPERAND (expr, 0)))));
}
}
case NOP_EXPR:
/* If truncating after truncating, might as well do all at once.
If truncating after extending, we may get rid of wasted work. */
return convert (type, get_unwidened (TREE_OPERAND (expr, 0), type));
case COND_EXPR:
/* Can treat the two alternative values like the operands
of an arithmetic expression. */
{
tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
tree arg2 = get_unwidened (TREE_OPERAND (expr, 2), type);
if (outprec >= BITS_PER_WORD
|| TRULY_NOOP_TRUNCATION (outprec, inprec)
|| inprec > TYPE_PRECISION (TREE_TYPE (arg1))
|| inprec > TYPE_PRECISION (TREE_TYPE (arg2)))
{
/* Do the arithmetic in type TYPEX,
then convert result to TYPE. */
register tree typex = type;
/* Can't do arithmetic in enumeral types
so use an integer type that will hold the values. */
if (TREE_CODE (typex) == ENUMERAL_TYPE)
typex = type_for_size (TYPE_PRECISION (typex),
TREE_UNSIGNED (typex));
/* But now perhaps TYPEX is as wide as INPREC.
In that case, do nothing special here.
(Otherwise would recurse infinitely in convert. */
if (TYPE_PRECISION (typex) != inprec)
{
/* Don't do unsigned arithmetic where signed was wanted,
or vice versa. */
typex = (TREE_UNSIGNED (TREE_TYPE (expr))
? unsigned_type (typex) : signed_type (typex));
return convert (type,
fold (build (COND_EXPR, typex,
TREE_OPERAND (expr, 0),
convert (typex, arg1),
convert (typex, arg2))));
}
else
/* It is sometimes worthwhile
to push the narrowing down through the conditional. */
return fold (build (COND_EXPR, type,
TREE_OPERAND (expr, 0),
convert (type, TREE_OPERAND (expr, 1)),
convert (type, TREE_OPERAND (expr, 2))));
}
}
}
return build1 (NOP_EXPR, type, expr);
}
if (form == REAL_TYPE)
return build1 (FIX_TRUNC_EXPR, type, expr);
if (form == COMPLEX_TYPE)
return convert (type, fold (build1 (REALPART_EXPR,
TREE_TYPE (TREE_TYPE (expr)), expr)));
error ("aggregate value used where an integer was expected");
{
register tree tem = build_int_2 (0, 0);
TREE_TYPE (tem) = type;
return tem;
}
}
/* Convert EXPR to the complex type TYPE in the usual ways. */
tree
convert_to_complex (type, expr)
tree type, expr;
{
register enum tree_code form = TREE_CODE (TREE_TYPE (expr));
tree subtype = TREE_TYPE (type);
if (form == REAL_TYPE || form == INTEGER_TYPE || form == ENUMERAL_TYPE)
{
expr = convert (subtype, expr);
return build (COMPLEX_EXPR, type, expr,
convert (subtype, integer_zero_node));
}
if (form == COMPLEX_TYPE)
{
tree elt_type = TREE_TYPE (TREE_TYPE (expr));
if (TYPE_MAIN_VARIANT (elt_type) == TYPE_MAIN_VARIANT (subtype))
return expr;
else if (TREE_CODE (expr) == COMPLEX_EXPR)
return fold (build (COMPLEX_EXPR,
type,
convert (subtype, TREE_OPERAND (expr, 0)),
convert (subtype, TREE_OPERAND (expr, 1))));
else
{
expr = save_expr (expr);
return fold (build (COMPLEX_EXPR,
type,
convert (subtype,
fold (build1 (REALPART_EXPR,
TREE_TYPE (TREE_TYPE (expr)),
expr))),
convert (subtype,
fold (build1 (IMAGPART_EXPR,
TREE_TYPE (TREE_TYPE (expr)),
expr)))));
}
}
if (form == POINTER_TYPE)
error ("pointer value used where a complex was expected");
else
error ("aggregate value used where a complex was expected");
return build (COMPLEX_EXPR, type,
convert (subtype, integer_zero_node),
convert (subtype, integer_zero_node));
}

8546
gnu/usr.bin/cc/cc_int/cse.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

10192
gnu/usr.bin/cc/cc_int/expr.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2793
gnu/usr.bin/cc/cc_int/flow.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,94 @@
/* getpwd.c - get the working directory */
#include "config.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef errno
extern int errno;
#endif
/* Virtually every UN*X system now in common use (except for pre-4.3-tahoe
BSD systems) now provides getcwd as called for by POSIX. Allow for
the few exceptions to the general rule here. */
#if !(defined (POSIX) || defined (USG) || defined (VMS))
#include <sys/param.h>
extern char *getwd ();
#define getcwd(buf,len) getwd(buf)
#define GUESSPATHLEN (MAXPATHLEN + 1)
#else /* (defined (USG) || defined (VMS)) */
extern char *getcwd ();
/* We actually use this as a starting point, not a limit. */
#define GUESSPATHLEN 100
#endif /* (defined (USG) || defined (VMS)) */
char *getenv ();
char *xmalloc ();
#ifndef VMS
/* Get the working directory. Use the PWD environment variable if it's
set correctly, since this is faster and gives more uniform answers
to the user. Yield the working directory if successful; otherwise,
yield 0 and set errno. */
char *
getpwd ()
{
static char *pwd;
static int failure_errno;
char *p = pwd;
size_t s;
struct stat dotstat, pwdstat;
if (!p && !(errno = failure_errno))
{
if (! ((p = getenv ("PWD")) != 0
&& *p == '/'
&& stat (p, &pwdstat) == 0
&& stat (".", &dotstat) == 0
&& dotstat.st_ino == pwdstat.st_ino
&& dotstat.st_dev == pwdstat.st_dev))
/* The shortcut didn't work. Try the slow, ``sure'' way. */
for (s = GUESSPATHLEN; ! getcwd (p = xmalloc (s), s); s *= 2)
{
int e = errno;
free (p);
#ifdef ERANGE
if (e != ERANGE)
#endif
{
errno = failure_errno = e;
p = 0;
break;
}
}
/* Cache the result. This assumes that the program does
not invoke chdir between calls to getpwd. */
pwd = p;
}
return p;
}
#else /* VMS */
#ifndef MAXPATHLEN
#define MAXPATHLEN 255
#endif
char *
getpwd ()
{
static char *pwd = 0;
if (!pwd) pwd = getcwd (xmalloc (MAXPATHLEN+1), MAXPATHLEN+1);
return pwd;
}
#endif /* VMS */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
/* Generated automatically by the program `genattrtab'
from the machine description file `md'. */
#include "config.h"
#include "rtl.h"
#include "insn-config.h"
#include "recog.h"
#include "regs.h"
#include "real.h"
#include "output.h"
#include "insn-attr.h"
#define operands recog_operand

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,533 @@
/* Generated automatically by the program `genextract'
from the machine description file `md'. */
#include "config.h"
#include "rtl.h"
static rtx junk;
extern rtx recog_operand[];
extern rtx *recog_operand_loc[];
extern rtx *recog_dup_loc[];
extern char recog_dup_num[];
extern
#ifdef __GNUC__
__volatile__
#endif
void fatal_insn_not_found ();
void
insn_extract (insn)
rtx insn;
{
register rtx *ro = recog_operand;
register rtx **ro_loc = recog_operand_loc;
rtx pat = PATTERN (insn);
switch (INSN_CODE (insn))
{
case -1:
fatal_insn_not_found (insn);
case 308:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0, 0), 0));
ro[2] = *(ro_loc[2] = &XVECEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0, 1));
ro[3] = *(ro_loc[3] = &XVECEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0, 2));
recog_dup_loc[0] = &XEXP (XVECEXP (pat, 0, 1), 0);
recog_dup_num[0] = 1;
break;
case 306:
case 303:
case 302:
case 300:
case 299:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XEXP (pat, 1), 1), 0));
ro[3] = *(ro_loc[3] = &XEXP (pat, 1));
break;
case 305:
case 301:
case 298:
case 297:
case 295:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (pat, 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 1));
ro[3] = *(ro_loc[3] = &XEXP (pat, 1));
break;
case 304:
case 296:
case 294:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 1));
ro[3] = *(ro_loc[3] = &XEXP (pat, 1));
break;
case 289:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 2), 0));
recog_dup_loc[0] = &XEXP (XVECEXP (pat, 0, 5), 0);
recog_dup_num[0] = 2;
recog_dup_loc[1] = &XEXP (XVECEXP (pat, 0, 4), 0);
recog_dup_num[1] = 1;
recog_dup_loc[2] = &XEXP (XVECEXP (pat, 0, 3), 0);
recog_dup_num[2] = 0;
break;
case 288:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1), 0));
ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 1), 0));
ro[4] = *(ro_loc[4] = &XEXP (XVECEXP (pat, 0, 2), 0));
recog_dup_loc[0] = &XEXP (XVECEXP (pat, 0, 5), 0);
recog_dup_num[0] = 3;
recog_dup_loc[1] = &XEXP (XVECEXP (pat, 0, 4), 0);
recog_dup_num[1] = 2;
recog_dup_loc[2] = &XEXP (XVECEXP (pat, 0, 3), 0);
recog_dup_num[2] = 1;
break;
case 286:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 2), 0));
ro[4] = *(ro_loc[4] = &XEXP (XVECEXP (pat, 0, 3), 0));
recog_dup_loc[0] = &XEXP (XVECEXP (pat, 0, 5), 0);
recog_dup_num[0] = 1;
recog_dup_loc[1] = &XEXP (XVECEXP (pat, 0, 4), 0);
recog_dup_num[1] = 0;
break;
case 284:
case 283:
break;
case 282:
ro[0] = *(ro_loc[0] = &XVECEXP (pat, 0, 0));
break;
case 280:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 0), 0));
ro[1] = *(ro_loc[1] = &XVECEXP (pat, 0, 1));
ro[2] = *(ro_loc[2] = &XVECEXP (pat, 0, 2));
break;
case 279:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XVECEXP (pat, 0, 1));
ro[2] = *(ro_loc[2] = &XVECEXP (pat, 0, 2));
break;
case 277:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (pat, 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 1));
break;
case 274:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
ro[3] = const0_rtx;
ro_loc[3] = &junk;
ro[4] = *(ro_loc[4] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 1), 1));
break;
case 273:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
ro[3] = const0_rtx;
ro_loc[3] = &junk;
ro[4] = *(ro_loc[4] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 1), 1));
break;
case 268:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (pat, 0, 0), 1));
ro[2] = const0_rtx;
ro_loc[2] = &junk;
ro[3] = *(ro_loc[3] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 1), 1));
break;
case 267:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (pat, 0, 0), 1));
ro[2] = const0_rtx;
ro_loc[2] = &junk;
ro[3] = *(ro_loc[3] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 1), 1));
break;
case 265:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 1));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 0), 0));
break;
case 264:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1), 0), 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1), 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
break;
case 261:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (pat, 1), 0));
break;
case 260:
case 259:
case 258:
case 257:
case 256:
case 255:
case 254:
case 253:
case 252:
case 251:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XEXP (pat, 1), 2), 0));
break;
case 250:
case 248:
case 246:
case 244:
case 242:
case 240:
case 238:
case 236:
case 234:
case 232:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XEXP (pat, 1), 1), 0));
break;
case 230:
case 228:
case 226:
case 224:
case 222:
case 220:
case 218:
case 216:
case 214:
case 212:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
break;
case 210:
case 209:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (pat, 1), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 1));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 2));
break;
case 208:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (pat, 1), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 2));
break;
case 207:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XEXP (pat, 1), 1), 1));
break;
case 206:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (pat, 1), 0), 1));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 1));
break;
case 205:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (pat, 0), 0));
ro[1] = const0_rtx;
ro_loc[1] = &junk;
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 0), 2));
ro[3] = *(ro_loc[3] = &XEXP (pat, 1));
break;
case 195:
case 189:
case 183:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
recog_dup_loc[0] = &XEXP (XVECEXP (pat, 0, 1), 0);
recog_dup_num[0] = 2;
break;
case 177:
case 174:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (XEXP (pat, 1), 0, 0), 0));
break;
case 176:
case 175:
case 173:
case 172:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XVECEXP (XEXP (pat, 1), 0, 0));
break;
case 293:
case 291:
case 171:
case 170:
case 168:
case 165:
case 163:
case 160:
case 158:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (pat, 1), 0), 0));
break;
case 142:
case 141:
case 140:
case 139:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 1), 0));
recog_dup_loc[0] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 1), 0);
recog_dup_num[0] = 1;
recog_dup_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 1), 1), 1);
recog_dup_num[1] = 2;
break;
case 130:
case 129:
case 128:
case 127:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (pat, 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (XEXP (pat, 1), 1), 0));
break;
case 276:
case 204:
case 203:
case 202:
case 201:
case 200:
case 199:
case 198:
case 197:
case 196:
case 194:
case 192:
case 191:
case 190:
case 188:
case 186:
case 185:
case 184:
case 182:
case 151:
case 150:
case 149:
case 148:
case 147:
case 146:
case 145:
case 144:
case 143:
case 135:
case 134:
case 126:
case 125:
case 124:
case 123:
case 119:
case 118:
case 117:
case 116:
case 111:
case 110:
case 109:
case 108:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XEXP (pat, 1), 1));
break;
case 95:
case 94:
case 93:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 2), 0));
ro[4] = *(ro_loc[4] = &XEXP (XVECEXP (pat, 0, 3), 0));
break;
case 89:
case 88:
case 87:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 2), 0));
ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 3), 0));
ro[4] = *(ro_loc[4] = &XEXP (XVECEXP (pat, 0, 4), 0));
recog_dup_loc[0] = &XEXP (XVECEXP (pat, 0, 1), 0);
recog_dup_num[0] = 1;
break;
case 78:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
break;
case 180:
case 179:
case 178:
case 169:
case 167:
case 166:
case 164:
case 162:
case 161:
case 159:
case 157:
case 156:
case 155:
case 154:
case 153:
case 152:
case 107:
case 106:
case 105:
case 104:
case 103:
case 102:
case 80:
case 79:
case 76:
case 75:
case 74:
case 73:
case 72:
case 71:
case 70:
case 69:
case 68:
case 67:
case 66:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 0));
break;
case 62:
case 59:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (pat, 0, 0), 1));
recog_dup_loc[0] = &XEXP (XVECEXP (pat, 0, 1), 0);
recog_dup_num[0] = 1;
recog_dup_loc[1] = &XEXP (XVECEXP (pat, 0, 1), 1);
recog_dup_num[1] = 0;
break;
case 271:
case 55:
case 52:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (pat, 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (pat, 1));
break;
case 270:
case 112:
case 65:
case 64:
case 63:
case 61:
case 60:
case 58:
case 57:
case 56:
case 54:
case 53:
case 51:
case 50:
case 49:
case 47:
case 46:
ro[0] = *(ro_loc[0] = &XEXP (pat, 0));
ro[1] = *(ro_loc[1] = &XEXP (pat, 1));
break;
case 33:
case 29:
case 23:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 1), 0));
break;
case 32:
case 28:
case 26:
case 20:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 0), 1));
ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 1), 0));
break;
case 31:
case 27:
case 25:
case 22:
case 21:
case 19:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1), 0));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 0), 1));
ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 1), 0));
break;
case 30:
case 24:
case 18:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 1));
ro[2] = *(ro_loc[2] = &XEXP (XVECEXP (pat, 0, 0), 1));
ro[3] = *(ro_loc[3] = &XEXP (XVECEXP (pat, 0, 1), 0));
break;
case 45:
case 44:
case 43:
case 16:
case 14:
case 12:
ro[0] = *(ro_loc[0] = &XEXP (XEXP (pat, 1), 0));
ro[1] = *(ro_loc[1] = &XEXP (XEXP (pat, 1), 1));
break;
case 10:
case 8:
case 6:
ro[0] = *(ro_loc[0] = &XEXP (XVECEXP (pat, 0, 0), 1));
ro[1] = *(ro_loc[1] = &XEXP (XVECEXP (pat, 0, 1), 0));
break;
case 262:
case 4:
case 2:
case 0:
ro[0] = *(ro_loc[0] = &XEXP (pat, 1));
break;
default:
abort ();
}
}

View File

@ -0,0 +1,216 @@
/* Generated automatically by the program `genopinit'
from the machine description file `md'. */
#include "config.h"
#include "rtl.h"
#include "flags.h"
#include "insn-flags.h"
#include "insn-codes.h"
#include "insn-config.h"
#include "recog.h"
#include "expr.h"
#include "reload.h"
void
init_all_optabs ()
{
tst_optab->handlers[(int) SImode].insn_code = CODE_FOR_tstsi;
tst_optab->handlers[(int) HImode].insn_code = CODE_FOR_tsthi;
tst_optab->handlers[(int) QImode].insn_code = CODE_FOR_tstqi;
if (HAVE_tstsf)
tst_optab->handlers[(int) SFmode].insn_code = CODE_FOR_tstsf;
if (HAVE_tstdf)
tst_optab->handlers[(int) DFmode].insn_code = CODE_FOR_tstdf;
if (HAVE_tstxf)
tst_optab->handlers[(int) XFmode].insn_code = CODE_FOR_tstxf;
cmp_optab->handlers[(int) SImode].insn_code = CODE_FOR_cmpsi;
cmp_optab->handlers[(int) HImode].insn_code = CODE_FOR_cmphi;
cmp_optab->handlers[(int) QImode].insn_code = CODE_FOR_cmpqi;
if (HAVE_cmpxf)
cmp_optab->handlers[(int) XFmode].insn_code = CODE_FOR_cmpxf;
if (HAVE_cmpdf)
cmp_optab->handlers[(int) DFmode].insn_code = CODE_FOR_cmpdf;
if (HAVE_cmpsf)
cmp_optab->handlers[(int) SFmode].insn_code = CODE_FOR_cmpsf;
mov_optab->handlers[(int) SImode].insn_code = CODE_FOR_movsi;
mov_optab->handlers[(int) HImode].insn_code = CODE_FOR_movhi;
movstrict_optab->handlers[(int) HImode].insn_code = CODE_FOR_movstricthi;
mov_optab->handlers[(int) QImode].insn_code = CODE_FOR_movqi;
movstrict_optab->handlers[(int) QImode].insn_code = CODE_FOR_movstrictqi;
mov_optab->handlers[(int) SFmode].insn_code = CODE_FOR_movsf;
mov_optab->handlers[(int) DFmode].insn_code = CODE_FOR_movdf;
mov_optab->handlers[(int) XFmode].insn_code = CODE_FOR_movxf;
mov_optab->handlers[(int) DImode].insn_code = CODE_FOR_movdi;
extendtab[(int) SImode][(int) HImode][1] = CODE_FOR_zero_extendhisi2;
extendtab[(int) HImode][(int) QImode][1] = CODE_FOR_zero_extendqihi2;
extendtab[(int) SImode][(int) QImode][1] = CODE_FOR_zero_extendqisi2;
extendtab[(int) DImode][(int) SImode][1] = CODE_FOR_zero_extendsidi2;
extendtab[(int) DImode][(int) SImode][0] = CODE_FOR_extendsidi2;
extendtab[(int) SImode][(int) HImode][0] = CODE_FOR_extendhisi2;
extendtab[(int) HImode][(int) QImode][0] = CODE_FOR_extendqihi2;
extendtab[(int) SImode][(int) QImode][0] = CODE_FOR_extendqisi2;
if (HAVE_extendsfdf2)
extendtab[(int) DFmode][(int) SFmode][0] = CODE_FOR_extendsfdf2;
if (HAVE_extenddfxf2)
extendtab[(int) XFmode][(int) DFmode][0] = CODE_FOR_extenddfxf2;
if (HAVE_extendsfxf2)
extendtab[(int) XFmode][(int) SFmode][0] = CODE_FOR_extendsfxf2;
if (HAVE_fixuns_truncxfsi2)
fixtrunctab[(int) XFmode][(int) SImode][1] = CODE_FOR_fixuns_truncxfsi2;
if (HAVE_fixuns_truncdfsi2)
fixtrunctab[(int) DFmode][(int) SImode][1] = CODE_FOR_fixuns_truncdfsi2;
if (HAVE_fixuns_truncsfsi2)
fixtrunctab[(int) SFmode][(int) SImode][1] = CODE_FOR_fixuns_truncsfsi2;
if (HAVE_fix_truncxfdi2)
fixtrunctab[(int) XFmode][(int) DImode][0] = CODE_FOR_fix_truncxfdi2;
if (HAVE_fix_truncdfdi2)
fixtrunctab[(int) DFmode][(int) DImode][0] = CODE_FOR_fix_truncdfdi2;
if (HAVE_fix_truncsfdi2)
fixtrunctab[(int) SFmode][(int) DImode][0] = CODE_FOR_fix_truncsfdi2;
if (HAVE_fix_truncxfsi2)
fixtrunctab[(int) XFmode][(int) SImode][0] = CODE_FOR_fix_truncxfsi2;
if (HAVE_fix_truncdfsi2)
fixtrunctab[(int) DFmode][(int) SImode][0] = CODE_FOR_fix_truncdfsi2;
if (HAVE_fix_truncsfsi2)
fixtrunctab[(int) SFmode][(int) SImode][0] = CODE_FOR_fix_truncsfsi2;
if (HAVE_floatsisf2)
floattab[(int) SFmode][(int) SImode][0] = CODE_FOR_floatsisf2;
if (HAVE_floatdisf2)
floattab[(int) SFmode][(int) DImode][0] = CODE_FOR_floatdisf2;
if (HAVE_floatsidf2)
floattab[(int) DFmode][(int) SImode][0] = CODE_FOR_floatsidf2;
if (HAVE_floatdidf2)
floattab[(int) DFmode][(int) DImode][0] = CODE_FOR_floatdidf2;
if (HAVE_floatsixf2)
floattab[(int) XFmode][(int) SImode][0] = CODE_FOR_floatsixf2;
if (HAVE_floatdixf2)
floattab[(int) XFmode][(int) DImode][0] = CODE_FOR_floatdixf2;
add_optab->handlers[(int) DImode].insn_code = CODE_FOR_adddi3;
add_optab->handlers[(int) SImode].insn_code = CODE_FOR_addsi3;
add_optab->handlers[(int) HImode].insn_code = CODE_FOR_addhi3;
add_optab->handlers[(int) QImode].insn_code = CODE_FOR_addqi3;
if (HAVE_addxf3)
add_optab->handlers[(int) XFmode].insn_code = CODE_FOR_addxf3;
if (HAVE_adddf3)
add_optab->handlers[(int) DFmode].insn_code = CODE_FOR_adddf3;
if (HAVE_addsf3)
add_optab->handlers[(int) SFmode].insn_code = CODE_FOR_addsf3;
sub_optab->handlers[(int) DImode].insn_code = CODE_FOR_subdi3;
sub_optab->handlers[(int) SImode].insn_code = CODE_FOR_subsi3;
sub_optab->handlers[(int) HImode].insn_code = CODE_FOR_subhi3;
sub_optab->handlers[(int) QImode].insn_code = CODE_FOR_subqi3;
if (HAVE_subxf3)
sub_optab->handlers[(int) XFmode].insn_code = CODE_FOR_subxf3;
if (HAVE_subdf3)
sub_optab->handlers[(int) DFmode].insn_code = CODE_FOR_subdf3;
if (HAVE_subsf3)
sub_optab->handlers[(int) SFmode].insn_code = CODE_FOR_subsf3;
smul_optab->handlers[(int) HImode].insn_code = CODE_FOR_mulhi3;
smul_optab->handlers[(int) SImode].insn_code = CODE_FOR_mulsi3;
umul_widen_optab->handlers[(int) HImode].insn_code = CODE_FOR_umulqihi3;
smul_widen_optab->handlers[(int) HImode].insn_code = CODE_FOR_mulqihi3;
umul_widen_optab->handlers[(int) DImode].insn_code = CODE_FOR_umulsidi3;
smul_widen_optab->handlers[(int) DImode].insn_code = CODE_FOR_mulsidi3;
if (HAVE_mulxf3)
smul_optab->handlers[(int) XFmode].insn_code = CODE_FOR_mulxf3;
if (HAVE_muldf3)
smul_optab->handlers[(int) DFmode].insn_code = CODE_FOR_muldf3;
if (HAVE_mulsf3)
smul_optab->handlers[(int) SFmode].insn_code = CODE_FOR_mulsf3;
sdiv_optab->handlers[(int) QImode].insn_code = CODE_FOR_divqi3;
udiv_optab->handlers[(int) QImode].insn_code = CODE_FOR_udivqi3;
if (HAVE_divxf3)
flodiv_optab->handlers[(int) XFmode].insn_code = CODE_FOR_divxf3;
if (HAVE_divdf3)
flodiv_optab->handlers[(int) DFmode].insn_code = CODE_FOR_divdf3;
if (HAVE_divsf3)
flodiv_optab->handlers[(int) SFmode].insn_code = CODE_FOR_divsf3;
sdivmod_optab->handlers[(int) SImode].insn_code = CODE_FOR_divmodsi4;
sdivmod_optab->handlers[(int) HImode].insn_code = CODE_FOR_divmodhi4;
udivmod_optab->handlers[(int) SImode].insn_code = CODE_FOR_udivmodsi4;
udivmod_optab->handlers[(int) HImode].insn_code = CODE_FOR_udivmodhi4;
and_optab->handlers[(int) SImode].insn_code = CODE_FOR_andsi3;
and_optab->handlers[(int) HImode].insn_code = CODE_FOR_andhi3;
and_optab->handlers[(int) QImode].insn_code = CODE_FOR_andqi3;
ior_optab->handlers[(int) SImode].insn_code = CODE_FOR_iorsi3;
ior_optab->handlers[(int) HImode].insn_code = CODE_FOR_iorhi3;
ior_optab->handlers[(int) QImode].insn_code = CODE_FOR_iorqi3;
xor_optab->handlers[(int) SImode].insn_code = CODE_FOR_xorsi3;
xor_optab->handlers[(int) HImode].insn_code = CODE_FOR_xorhi3;
xor_optab->handlers[(int) QImode].insn_code = CODE_FOR_xorqi3;
neg_optab->handlers[(int) DImode].insn_code = CODE_FOR_negdi2;
neg_optab->handlers[(int) SImode].insn_code = CODE_FOR_negsi2;
neg_optab->handlers[(int) HImode].insn_code = CODE_FOR_neghi2;
neg_optab->handlers[(int) QImode].insn_code = CODE_FOR_negqi2;
if (HAVE_negsf2)
neg_optab->handlers[(int) SFmode].insn_code = CODE_FOR_negsf2;
if (HAVE_negdf2)
neg_optab->handlers[(int) DFmode].insn_code = CODE_FOR_negdf2;
if (HAVE_negxf2)
neg_optab->handlers[(int) XFmode].insn_code = CODE_FOR_negxf2;
if (HAVE_abssf2)
abs_optab->handlers[(int) SFmode].insn_code = CODE_FOR_abssf2;
if (HAVE_absdf2)
abs_optab->handlers[(int) DFmode].insn_code = CODE_FOR_absdf2;
if (HAVE_absxf2)
abs_optab->handlers[(int) XFmode].insn_code = CODE_FOR_absxf2;
if (HAVE_sqrtsf2)
sqrt_optab->handlers[(int) SFmode].insn_code = CODE_FOR_sqrtsf2;
if (HAVE_sqrtdf2)
sqrt_optab->handlers[(int) DFmode].insn_code = CODE_FOR_sqrtdf2;
if (HAVE_sqrtxf2)
sqrt_optab->handlers[(int) XFmode].insn_code = CODE_FOR_sqrtxf2;
if (HAVE_sindf2)
sin_optab->handlers[(int) DFmode].insn_code = CODE_FOR_sindf2;
if (HAVE_sinsf2)
sin_optab->handlers[(int) SFmode].insn_code = CODE_FOR_sinsf2;
if (HAVE_cosdf2)
cos_optab->handlers[(int) DFmode].insn_code = CODE_FOR_cosdf2;
if (HAVE_cossf2)
cos_optab->handlers[(int) SFmode].insn_code = CODE_FOR_cossf2;
one_cmpl_optab->handlers[(int) SImode].insn_code = CODE_FOR_one_cmplsi2;
one_cmpl_optab->handlers[(int) HImode].insn_code = CODE_FOR_one_cmplhi2;
one_cmpl_optab->handlers[(int) QImode].insn_code = CODE_FOR_one_cmplqi2;
ashl_optab->handlers[(int) DImode].insn_code = CODE_FOR_ashldi3;
ashl_optab->handlers[(int) SImode].insn_code = CODE_FOR_ashlsi3;
ashl_optab->handlers[(int) HImode].insn_code = CODE_FOR_ashlhi3;
ashl_optab->handlers[(int) QImode].insn_code = CODE_FOR_ashlqi3;
ashr_optab->handlers[(int) DImode].insn_code = CODE_FOR_ashrdi3;
ashr_optab->handlers[(int) SImode].insn_code = CODE_FOR_ashrsi3;
ashr_optab->handlers[(int) HImode].insn_code = CODE_FOR_ashrhi3;
ashr_optab->handlers[(int) QImode].insn_code = CODE_FOR_ashrqi3;
lshr_optab->handlers[(int) DImode].insn_code = CODE_FOR_lshrdi3;
lshr_optab->handlers[(int) SImode].insn_code = CODE_FOR_lshrsi3;
lshr_optab->handlers[(int) HImode].insn_code = CODE_FOR_lshrhi3;
lshr_optab->handlers[(int) QImode].insn_code = CODE_FOR_lshrqi3;
rotl_optab->handlers[(int) SImode].insn_code = CODE_FOR_rotlsi3;
rotl_optab->handlers[(int) HImode].insn_code = CODE_FOR_rotlhi3;
rotl_optab->handlers[(int) QImode].insn_code = CODE_FOR_rotlqi3;
rotr_optab->handlers[(int) SImode].insn_code = CODE_FOR_rotrsi3;
rotr_optab->handlers[(int) HImode].insn_code = CODE_FOR_rotrhi3;
rotr_optab->handlers[(int) QImode].insn_code = CODE_FOR_rotrqi3;
setcc_gen_code[(int) EQ] = CODE_FOR_seq;
setcc_gen_code[(int) NE] = CODE_FOR_sne;
setcc_gen_code[(int) GT] = CODE_FOR_sgt;
setcc_gen_code[(int) GTU] = CODE_FOR_sgtu;
setcc_gen_code[(int) LT] = CODE_FOR_slt;
setcc_gen_code[(int) LTU] = CODE_FOR_sltu;
setcc_gen_code[(int) GE] = CODE_FOR_sge;
setcc_gen_code[(int) GEU] = CODE_FOR_sgeu;
setcc_gen_code[(int) LE] = CODE_FOR_sle;
setcc_gen_code[(int) LEU] = CODE_FOR_sleu;
bcc_gen_fctn[(int) EQ] = gen_beq;
bcc_gen_fctn[(int) NE] = gen_bne;
bcc_gen_fctn[(int) GT] = gen_bgt;
bcc_gen_fctn[(int) GTU] = gen_bgtu;
bcc_gen_fctn[(int) LT] = gen_blt;
bcc_gen_fctn[(int) LTU] = gen_bltu;
bcc_gen_fctn[(int) GE] = gen_bge;
bcc_gen_fctn[(int) GEU] = gen_bgeu;
bcc_gen_fctn[(int) LE] = gen_ble;
bcc_gen_fctn[(int) LEU] = gen_bleu;
movstr_optab[(int) SImode] = CODE_FOR_movstrsi;
ffs_optab->handlers[(int) SImode].insn_code = CODE_FOR_ffssi2;
ffs_optab->handlers[(int) HImode].insn_code = CODE_FOR_ffshi2;
strlen_optab->handlers[(int) SImode].insn_code = CODE_FOR_strlensi;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
/* Generated automatically by the program `genpeep'
from the machine description file `md'. */
#include "config.h"
#include "rtl.h"
#include "regs.h"
#include "output.h"
#include "real.h"
extern rtx peep_operand[];
#define operands peep_operand
rtx
peephole (ins1)
rtx ins1;
{
rtx insn, x, pat;
int i;
if (NEXT_INSN (ins1)
&& GET_CODE (NEXT_INSN (ins1)) == BARRIER)
return 0;
return 0;
}
rtx peep_operand[2];

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4395
gnu/usr.bin/cc/cc_int/jump.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6587
gnu/usr.bin/cc/cc_int/loop.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,485 @@
/* obstack.c - subroutines used implicitly by object stack macros
Copyright (C) 1988, 89, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "obstack.h"
/* This is just to get __GNU_LIBRARY__ defined. */
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
#ifdef __STDC__
#define POINTER void *
#else
#define POINTER char *
#endif
/* Determine default alignment. */
struct fooalign {char x; double d;};
#define DEFAULT_ALIGNMENT \
((PTR_INT_TYPE) ((char *)&((struct fooalign *) 0)->d - (char *)0))
/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
But in fact it might be less smart and round addresses to as much as
DEFAULT_ROUNDING. So we prepare for it to do that. */
union fooround {long x; double d;};
#define DEFAULT_ROUNDING (sizeof (union fooround))
/* When we copy a long block of data, this is the unit to do it with.
On some machines, copying successive ints does not work;
in such a case, redefine COPYING_UNIT to `long' (if that works)
or `char' as a last resort. */
#ifndef COPYING_UNIT
#define COPYING_UNIT int
#endif
/* The non-GNU-C macros copy the obstack into this global variable
to avoid multiple evaluation. */
struct obstack *_obstack;
/* Define a macro that either calls functions with the traditional malloc/free
calling interface, or calls functions with the mmalloc/mfree interface
(that adds an extra first argument), based on the state of use_extra_arg.
For free, do not use ?:, since some compilers, like the MIPS compilers,
do not allow (expr) ? void : void. */
#define CALL_CHUNKFUN(h, size) \
(((h) -> use_extra_arg) \
? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
: (*(h)->chunkfun) ((size)))
#define CALL_FREEFUN(h, old_chunk) \
do { \
if ((h) -> use_extra_arg) \
(*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
else \
(*(h)->freefun) ((old_chunk)); \
} while (0)
/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
Objects start on multiples of ALIGNMENT (0 means use default).
CHUNKFUN is the function to use to allocate chunks,
and FREEFUN the function to free them.
Return nonzero if successful, zero if out of memory.
To recover from an out of memory error,
free up some memory, then call this again. */
int
_obstack_begin (h, size, alignment, chunkfun, freefun)
struct obstack *h;
int size;
int alignment;
POINTER (*chunkfun) ();
void (*freefun) ();
{
register struct _obstack_chunk* chunk; /* points to new chunk */
if (alignment == 0)
alignment = DEFAULT_ALIGNMENT;
if (size == 0)
/* Default size is what GNU malloc can fit in a 4096-byte block. */
{
/* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
Use the values for range checking, because if range checking is off,
the extra bytes won't be missed terribly, but if range checking is on
and we used a larger request, a whole extra 4096 bytes would be
allocated.
These number are irrelevant to the new GNU malloc. I suspect it is
less sensitive to the size of the request. */
int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ 4 + DEFAULT_ROUNDING - 1)
& ~(DEFAULT_ROUNDING - 1));
size = 4096 - extra;
}
h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
h->freefun = freefun;
h->chunk_size = size;
h->alignment_mask = alignment - 1;
h->use_extra_arg = 0;
chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
if (!chunk)
{
h->alloc_failed = 1;
return 0;
}
h->alloc_failed = 0;
h->next_free = h->object_base = chunk->contents;
h->chunk_limit = chunk->limit
= (char *) chunk + h->chunk_size;
chunk->prev = 0;
/* The initial chunk now contains no empty object. */
h->maybe_empty_object = 0;
return 1;
}
int
_obstack_begin_1 (h, size, alignment, chunkfun, freefun, arg)
struct obstack *h;
int size;
int alignment;
POINTER (*chunkfun) ();
void (*freefun) ();
POINTER arg;
{
register struct _obstack_chunk* chunk; /* points to new chunk */
if (alignment == 0)
alignment = DEFAULT_ALIGNMENT;
if (size == 0)
/* Default size is what GNU malloc can fit in a 4096-byte block. */
{
/* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
Use the values for range checking, because if range checking is off,
the extra bytes won't be missed terribly, but if range checking is on
and we used a larger request, a whole extra 4096 bytes would be
allocated.
These number are irrelevant to the new GNU malloc. I suspect it is
less sensitive to the size of the request. */
int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+ 4 + DEFAULT_ROUNDING - 1)
& ~(DEFAULT_ROUNDING - 1));
size = 4096 - extra;
}
h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
h->freefun = freefun;
h->chunk_size = size;
h->alignment_mask = alignment - 1;
h->extra_arg = arg;
h->use_extra_arg = 1;
chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
if (!chunk)
{
h->alloc_failed = 1;
return 0;
}
h->alloc_failed = 0;
h->next_free = h->object_base = chunk->contents;
h->chunk_limit = chunk->limit
= (char *) chunk + h->chunk_size;
chunk->prev = 0;
/* The initial chunk now contains no empty object. */
h->maybe_empty_object = 0;
return 1;
}
/* Allocate a new current chunk for the obstack *H
on the assumption that LENGTH bytes need to be added
to the current object, or a new object of length LENGTH allocated.
Copies any partial object from the end of the old chunk
to the beginning of the new one. */
void
_obstack_newchunk (h, length)
struct obstack *h;
int length;
{
register struct _obstack_chunk* old_chunk = h->chunk;
register struct _obstack_chunk* new_chunk;
register long new_size;
register int obj_size = h->next_free - h->object_base;
register int i;
int already;
/* Compute size for new chunk. */
new_size = (obj_size + length) + (obj_size >> 3) + 100;
if (new_size < h->chunk_size)
new_size = h->chunk_size;
/* Allocate and initialize the new chunk. */
new_chunk = CALL_CHUNKFUN (h, new_size);
if (!new_chunk)
{
h->alloc_failed = 1;
return;
}
h->alloc_failed = 0;
h->chunk = new_chunk;
new_chunk->prev = old_chunk;
new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
/* Move the existing object to the new chunk.
Word at a time is fast and is safe if the object
is sufficiently aligned. */
if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
{
for (i = obj_size / sizeof (COPYING_UNIT) - 1;
i >= 0; i--)
((COPYING_UNIT *)new_chunk->contents)[i]
= ((COPYING_UNIT *)h->object_base)[i];
/* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
but that can cross a page boundary on a machine
which does not do strict alignment for COPYING_UNITS. */
already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
}
else
already = 0;
/* Copy remaining bytes one by one. */
for (i = already; i < obj_size; i++)
new_chunk->contents[i] = h->object_base[i];
/* If the object just copied was the only data in OLD_CHUNK,
free that chunk and remove it from the chain.
But not if that chunk might contain an empty object. */
if (h->object_base == old_chunk->contents && ! h->maybe_empty_object)
{
new_chunk->prev = old_chunk->prev;
CALL_FREEFUN (h, old_chunk);
}
h->object_base = new_chunk->contents;
h->next_free = h->object_base + obj_size;
/* The new chunk certainly contains no empty object yet. */
h->maybe_empty_object = 0;
}
/* Return nonzero if object OBJ has been allocated from obstack H.
This is here for debugging.
If you use it in a program, you are probably losing. */
#ifdef __STDC__
/* Suppress -Wmissing-prototypes warning. We don't want to declare this in
obstack.h because it is just for debugging. */
int _obstack_allocated_p (struct obstack *h, POINTER obj);
#endif
int
_obstack_allocated_p (h, obj)
struct obstack *h;
POINTER obj;
{
register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
register struct _obstack_chunk* plp; /* point to previous chunk if any */
lp = (h)->chunk;
/* We use >= rather than > since the object cannot be exactly at
the beginning of the chunk but might be an empty object exactly
at the end of an adjacent chunk. */
while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
{
plp = lp->prev;
lp = plp;
}
return lp != 0;
}
/* Free objects in obstack H, including OBJ and everything allocate
more recently than OBJ. If OBJ is zero, free everything in H. */
#undef obstack_free
/* This function has two names with identical definitions.
This is the first one, called from non-ANSI code. */
void
_obstack_free (h, obj)
struct obstack *h;
POINTER obj;
{
register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
register struct _obstack_chunk* plp; /* point to previous chunk if any */
lp = h->chunk;
/* We use >= because there cannot be an object at the beginning of a chunk.
But there can be an empty object at that address
at the end of another chunk. */
while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
{
plp = lp->prev;
CALL_FREEFUN (h, lp);
lp = plp;
/* If we switch chunks, we can't tell whether the new current
chunk contains an empty object, so assume that it may. */
h->maybe_empty_object = 1;
}
if (lp)
{
h->object_base = h->next_free = (char *)(obj);
h->chunk_limit = lp->limit;
h->chunk = lp;
}
else if (obj != 0)
/* obj is not in any of the chunks! */
abort ();
}
/* This function is used from ANSI code. */
void
obstack_free (h, obj)
struct obstack *h;
POINTER obj;
{
register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
register struct _obstack_chunk* plp; /* point to previous chunk if any */
lp = h->chunk;
/* We use >= because there cannot be an object at the beginning of a chunk.
But there can be an empty object at that address
at the end of another chunk. */
while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
{
plp = lp->prev;
CALL_FREEFUN (h, lp);
lp = plp;
/* If we switch chunks, we can't tell whether the new current
chunk contains an empty object, so assume that it may. */
h->maybe_empty_object = 1;
}
if (lp)
{
h->object_base = h->next_free = (char *)(obj);
h->chunk_limit = lp->limit;
h->chunk = lp;
}
else if (obj != 0)
/* obj is not in any of the chunks! */
abort ();
}
#if 0
/* These are now turned off because the applications do not use it
and it uses bcopy via obstack_grow, which causes trouble on sysV. */
/* Now define the functional versions of the obstack macros.
Define them to simply use the corresponding macros to do the job. */
#ifdef __STDC__
/* These function definitions do not work with non-ANSI preprocessors;
they won't pass through the macro names in parentheses. */
/* The function names appear in parentheses in order to prevent
the macro-definitions of the names from being expanded there. */
POINTER (obstack_base) (obstack)
struct obstack *obstack;
{
return obstack_base (obstack);
}
POINTER (obstack_next_free) (obstack)
struct obstack *obstack;
{
return obstack_next_free (obstack);
}
int (obstack_object_size) (obstack)
struct obstack *obstack;
{
return obstack_object_size (obstack);
}
int (obstack_room) (obstack)
struct obstack *obstack;
{
return obstack_room (obstack);
}
void (obstack_grow) (obstack, pointer, length)
struct obstack *obstack;
POINTER pointer;
int length;
{
obstack_grow (obstack, pointer, length);
}
void (obstack_grow0) (obstack, pointer, length)
struct obstack *obstack;
POINTER pointer;
int length;
{
obstack_grow0 (obstack, pointer, length);
}
void (obstack_1grow) (obstack, character)
struct obstack *obstack;
int character;
{
obstack_1grow (obstack, character);
}
void (obstack_blank) (obstack, length)
struct obstack *obstack;
int length;
{
obstack_blank (obstack, length);
}
void (obstack_1grow_fast) (obstack, character)
struct obstack *obstack;
int character;
{
obstack_1grow_fast (obstack, character);
}
void (obstack_blank_fast) (obstack, length)
struct obstack *obstack;
int length;
{
obstack_blank_fast (obstack, length);
}
POINTER (obstack_finish) (obstack)
struct obstack *obstack;
{
return obstack_finish (obstack);
}
POINTER (obstack_alloc) (obstack, length)
struct obstack *obstack;
int length;
{
return obstack_alloc (obstack, length);
}
POINTER (obstack_copy) (obstack, pointer, length)
struct obstack *obstack;
POINTER pointer;
int length;
{
return obstack_copy (obstack, pointer, length);
}
POINTER (obstack_copy0) (obstack, pointer, length)
struct obstack *obstack;
POINTER pointer;
int length;
{
return obstack_copy0 (obstack, pointer, length);
}
#endif /* __STDC__ */
#endif /* 0 */
#endif /* _LIBC or not __GNU_LIBRARY__. */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,328 @@
/* Print RTL for GNU C Compiler.
Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include <ctype.h>
#include <stdio.h>
#include "rtl.h"
/* How to print out a register name.
We don't use PRINT_REG because some definitions of PRINT_REG
don't work here. */
#ifndef DEBUG_PRINT_REG
#define DEBUG_PRINT_REG(RTX, CODE, FILE) \
fprintf ((FILE), "%d %s", REGNO (RTX), reg_names[REGNO (RTX)])
#endif
/* Array containing all of the register names */
#ifdef DEBUG_REGISTER_NAMES
static char *reg_names[] = DEBUG_REGISTER_NAMES;
#else
static char *reg_names[] = REGISTER_NAMES;
#endif
static FILE *outfile;
char spaces[] = " ";
static int sawclose = 0;
/* Names for patterns. Non-zero only when linked with insn-output.c. */
extern char **insn_name_ptr;
/* Print IN_RTX onto OUTFILE. This is the recursive part of printing. */
static void
print_rtx (in_rtx)
register rtx in_rtx;
{
static int indent;
register int i, j;
register char *format_ptr;
register int is_insn;
if (sawclose)
{
fprintf (outfile, "\n%s",
(spaces + (sizeof spaces - 1 - indent * 2)));
sawclose = 0;
}
if (in_rtx == 0)
{
fprintf (outfile, "(nil)");
sawclose = 1;
return;
}
/* print name of expression code */
fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx)));
if (in_rtx->in_struct)
fprintf (outfile, "/s");
if (in_rtx->volatil)
fprintf (outfile, "/v");
if (in_rtx->unchanging)
fprintf (outfile, "/u");
if (in_rtx->integrated)
fprintf (outfile, "/i");
if (GET_MODE (in_rtx) != VOIDmode)
{
/* Print REG_NOTE names for EXPR_LIST and INSN_LIST. */
if (GET_CODE (in_rtx) == EXPR_LIST || GET_CODE (in_rtx) == INSN_LIST)
fprintf (outfile, ":%s", GET_REG_NOTE_NAME (GET_MODE (in_rtx)));
else
fprintf (outfile, ":%s", GET_MODE_NAME (GET_MODE (in_rtx)));
}
is_insn = (GET_RTX_CLASS (GET_CODE (in_rtx)) == 'i');
format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
switch (*format_ptr++)
{
case 'S':
case 's':
if (XSTR (in_rtx, i) == 0)
fprintf (outfile, " \"\"");
else
fprintf (outfile, " (\"%s\")", XSTR (in_rtx, i));
sawclose = 1;
break;
/* 0 indicates a field for internal use that should not be printed. */
case '0':
break;
case 'e':
indent += 2;
if (!sawclose)
fprintf (outfile, " ");
print_rtx (XEXP (in_rtx, i));
indent -= 2;
break;
case 'E':
case 'V':
indent += 2;
if (sawclose)
{
fprintf (outfile, "\n%s",
(spaces + (sizeof spaces - 1 - indent * 2)));
sawclose = 0;
}
fprintf (outfile, "[ ");
if (NULL != XVEC (in_rtx, i))
{
indent += 2;
if (XVECLEN (in_rtx, i))
sawclose = 1;
for (j = 0; j < XVECLEN (in_rtx, i); j++)
print_rtx (XVECEXP (in_rtx, i, j));
indent -= 2;
}
if (sawclose)
fprintf (outfile, "\n%s",
(spaces + (sizeof spaces - 1 - indent * 2)));
fprintf (outfile, "] ");
sawclose = 1;
indent -= 2;
break;
case 'w':
fprintf (outfile,
#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
" %d",
#else
" %ld",
#endif
XWINT (in_rtx, i));
break;
case 'i':
{
register int value = XINT (in_rtx, i);
if (GET_CODE (in_rtx) == REG && value < FIRST_PSEUDO_REGISTER)
{
fputc (' ', outfile);
DEBUG_PRINT_REG (in_rtx, 0, outfile);
}
else
fprintf (outfile, " %d", value);
}
if (is_insn && &INSN_CODE (in_rtx) == &XINT (in_rtx, i)
&& insn_name_ptr
&& XINT (in_rtx, i) >= 0)
fprintf (outfile, " {%s}", insn_name_ptr[XINT (in_rtx, i)]);
sawclose = 0;
break;
/* Print NOTE_INSN names rather than integer codes. */
case 'n':
if (XINT (in_rtx, i) <= 0)
fprintf (outfile, " %s", GET_NOTE_INSN_NAME (XINT (in_rtx, i)));
else
fprintf (outfile, " %d", XINT (in_rtx, i));
sawclose = 0;
break;
case 'u':
if (XEXP (in_rtx, i) != NULL)
fprintf (outfile, " %d", INSN_UID (XEXP (in_rtx, i)));
else
fprintf (outfile, " 0");
sawclose = 0;
break;
case '*':
fprintf (outfile, " Unknown");
sawclose = 0;
break;
default:
fprintf (stderr,
"switch format wrong in rtl.print_rtx(). format was: %c.\n",
format_ptr[-1]);
abort ();
}
fprintf (outfile, ")");
sawclose = 1;
}
/* Call this function from the debugger to see what X looks like. */
void
debug_rtx (x)
rtx x;
{
outfile = stderr;
print_rtx (x);
fprintf (stderr, "\n");
}
/* Count of rtx's to print with debug_rtx_list.
This global exists because gdb user defined commands have no arguments. */
int debug_rtx_count = 0; /* 0 is treated as equivalent to 1 */
/* Call this function to print list from X on.
N is a count of the rtx's to print. Positive values print from the specified
rtx on. Negative values print a window around the rtx.
EG: -5 prints 2 rtx's on either side (in addition to the specified rtx). */
void
debug_rtx_list (x, n)
rtx x;
int n;
{
int i,count;
rtx insn;
count = n == 0 ? 1 : n < 0 ? -n : n;
/* If we are printing a window, back up to the start. */
if (n < 0)
for (i = count / 2; i > 0; i--)
{
if (PREV_INSN (x) == 0)
break;
x = PREV_INSN (x);
}
for (i = count, insn = x; i > 0 && insn != 0; i--, insn = NEXT_INSN (insn))
debug_rtx (insn);
}
/* Call this function to search an rtx list to find one with insn uid UID,
and then call debug_rtx_list to print it, using DEBUG_RTX_COUNT.
The found insn is returned to enable further debugging analysis. */
rtx
debug_rtx_find(x, uid)
rtx x;
int uid;
{
while (x != 0 && INSN_UID (x) != uid)
x = NEXT_INSN (x);
if (x != 0)
{
debug_rtx_list (x, debug_rtx_count);
return x;
}
else
{
fprintf (stderr, "insn uid %d not found\n", uid);
return 0;
}
}
/* External entry point for printing a chain of insns
starting with RTX_FIRST onto file OUTF.
A blank line separates insns.
If RTX_FIRST is not an insn, then it alone is printed, with no newline. */
void
print_rtl (outf, rtx_first)
FILE *outf;
rtx rtx_first;
{
register rtx tmp_rtx;
outfile = outf;
sawclose = 0;
if (rtx_first == 0)
fprintf (outf, "(nil)\n");
else
switch (GET_CODE (rtx_first))
{
case INSN:
case JUMP_INSN:
case CALL_INSN:
case NOTE:
case CODE_LABEL:
case BARRIER:
for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
{
print_rtx (tmp_rtx);
fprintf (outfile, "\n");
}
break;
default:
print_rtx (rtx_first);
}
}

View File

@ -0,0 +1,642 @@
/* Prints out tree in human readable form - GNU C-compiler
Copyright (C) 1990, 1991, 1993, 1994 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include "tree.h"
#include <stdio.h>
extern char **tree_code_name;
extern char *mode_name[];
void print_node ();
void indent_to ();
/* Define the hash table of nodes already seen.
Such nodes are not repeated; brief cross-references are used. */
#define HASH_SIZE 37
struct bucket
{
tree node;
struct bucket *next;
};
static struct bucket **table;
/* Print the node NODE on standard error, for debugging.
Most nodes referred to by this one are printed recursively
down to a depth of six. */
void
debug_tree (node)
tree node;
{
char *object = (char *) oballoc (0);
table = (struct bucket **) oballoc (HASH_SIZE * sizeof (struct bucket *));
bzero ((char *) table, HASH_SIZE * sizeof (struct bucket *));
print_node (stderr, "", node, 0);
table = 0;
obfree (object);
fprintf (stderr, "\n");
}
/* Print a node in brief fashion, with just the code, address and name. */
void
print_node_brief (file, prefix, node, indent)
FILE *file;
char *prefix;
tree node;
int indent;
{
char class;
if (node == 0)
return;
class = TREE_CODE_CLASS (TREE_CODE (node));
/* Always print the slot this node is in, and its code, address and
name if any. */
if (indent > 0)
fprintf (file, " ");
fprintf (file, "%s <%s ", prefix, tree_code_name[(int) TREE_CODE (node)]);
fprintf (file, HOST_PTR_PRINTF, (HOST_WIDE_INT) node);
if (class == 'd')
{
if (DECL_NAME (node))
fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node)));
}
else if (class == 't')
{
if (TYPE_NAME (node))
{
if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
fprintf (file, " %s", IDENTIFIER_POINTER (TYPE_NAME (node)));
else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
&& DECL_NAME (TYPE_NAME (node)))
fprintf (file, " %s",
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))));
}
}
if (TREE_CODE (node) == IDENTIFIER_NODE)
fprintf (file, " %s", IDENTIFIER_POINTER (node));
/* We might as well always print the value of an integer. */
if (TREE_CODE (node) == INTEGER_CST)
{
if (TREE_CONSTANT_OVERFLOW (node))
fprintf (file, " overflow");
if (TREE_INT_CST_HIGH (node) == 0)
fprintf (file, " %1u", TREE_INT_CST_LOW (node));
else if (TREE_INT_CST_HIGH (node) == -1
&& TREE_INT_CST_LOW (node) != 0)
fprintf (file, " -%1u", -TREE_INT_CST_LOW (node));
else
fprintf (file,
#if HOST_BITS_PER_WIDE_INT == 64
#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
" 0x%lx%016lx",
#else
" 0x%x%016x",
#endif
#else
#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
" 0x%lx%08lx",
#else
" 0x%x%08x",
#endif
#endif
TREE_INT_CST_HIGH (node), TREE_INT_CST_LOW (node));
}
if (TREE_CODE (node) == REAL_CST)
{
#ifndef REAL_IS_NOT_DOUBLE
fprintf (file, " %e", TREE_REAL_CST (node));
#else
{
int i;
unsigned char *p = (unsigned char *) &TREE_REAL_CST (node);
fprintf (file, " 0x");
for (i = 0; i < sizeof TREE_REAL_CST (node); i++)
fprintf (file, "%02x", *p++);
fprintf (file, "");
}
#endif /* REAL_IS_NOT_DOUBLE */
}
fprintf (file, ">");
}
void
indent_to (file, column)
FILE *file;
int column;
{
int i;
/* Since this is the long way, indent to desired column. */
if (column > 0)
fprintf (file, "\n");
for (i = 0; i < column; i++)
fprintf (file, " ");
}
/* Print the node NODE in full on file FILE, preceded by PREFIX,
starting in column INDENT. */
void
print_node (file, prefix, node, indent)
FILE *file;
char *prefix;
tree node;
int indent;
{
int hash;
struct bucket *b;
enum machine_mode mode;
char class;
int len;
int first_rtl;
int i;
if (node == 0)
return;
class = TREE_CODE_CLASS (TREE_CODE (node));
/* Don't get too deep in nesting. If the user wants to see deeper,
it is easy to use the address of a lowest-level node
as an argument in another call to debug_tree. */
if (indent > 24)
{
print_node_brief (file, prefix, node, indent);
return;
}
if (indent > 8 && (class == 't' || class == 'd'))
{
print_node_brief (file, prefix, node, indent);
return;
}
/* It is unsafe to look at any other filds of an ERROR_MARK node. */
if (TREE_CODE (node) == ERROR_MARK)
{
print_node_brief (file, prefix, node, indent);
return;
}
hash = ((unsigned HOST_WIDE_INT) node) % HASH_SIZE;
/* If node is in the table, just mention its address. */
for (b = table[hash]; b; b = b->next)
if (b->node == node)
{
print_node_brief (file, prefix, node, indent);
return;
}
/* Add this node to the table. */
b = (struct bucket *) oballoc (sizeof (struct bucket));
b->node = node;
b->next = table[hash];
table[hash] = b;
/* Indent to the specified column, since this is the long form. */
indent_to (file, indent);
/* Print the slot this node is in, and its code, and address. */
fprintf (file, "%s <%s ", prefix, tree_code_name[(int) TREE_CODE (node)]);
fprintf (file, HOST_PTR_PRINTF, (HOST_WIDE_INT) node);
/* Print the name, if any. */
if (class == 'd')
{
if (DECL_NAME (node))
fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node)));
}
else if (class == 't')
{
if (TYPE_NAME (node))
{
if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
fprintf (file, " %s", IDENTIFIER_POINTER (TYPE_NAME (node)));
else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
&& DECL_NAME (TYPE_NAME (node)))
fprintf (file, " %s",
IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))));
}
}
if (TREE_CODE (node) == IDENTIFIER_NODE)
fprintf (file, " %s", IDENTIFIER_POINTER (node));
if (TREE_CODE (node) == INTEGER_CST)
{
if (indent <= 4)
print_node_brief (file, "type", TREE_TYPE (node), indent + 4);
}
else
{
print_node (file, "type", TREE_TYPE (node), indent + 4);
if (TREE_TYPE (node))
indent_to (file, indent + 3);
print_obstack_name ((char *) node, file, "");
indent_to (file, indent + 3);
}
/* If a permanent object is in the wrong obstack, or the reverse, warn. */
if (object_permanent_p (node) != TREE_PERMANENT (node))
{
if (TREE_PERMANENT (node))
fputs (" !!permanent object in non-permanent obstack!!", file);
else
fputs (" !!non-permanent object in permanent obstack!!", file);
indent_to (file, indent + 3);
}
if (TREE_SIDE_EFFECTS (node))
fputs (" side-effects", file);
if (TREE_READONLY (node))
fputs (" readonly", file);
if (TREE_CONSTANT (node))
fputs (" constant", file);
if (TREE_ADDRESSABLE (node))
fputs (" addressable", file);
if (TREE_THIS_VOLATILE (node))
fputs (" volatile", file);
if (TREE_UNSIGNED (node))
fputs (" unsigned", file);
if (TREE_ASM_WRITTEN (node))
fputs (" asm_written", file);
if (TREE_USED (node))
fputs (" used", file);
if (TREE_RAISES (node))
fputs (" raises", file);
if (TREE_PERMANENT (node))
fputs (" permanent", file);
if (TREE_PUBLIC (node))
fputs (" public", file);
if (TREE_STATIC (node))
fputs (" static", file);
if (TREE_LANG_FLAG_0 (node))
fputs (" tree_0", file);
if (TREE_LANG_FLAG_1 (node))
fputs (" tree_1", file);
if (TREE_LANG_FLAG_2 (node))
fputs (" tree_2", file);
if (TREE_LANG_FLAG_3 (node))
fputs (" tree_3", file);
if (TREE_LANG_FLAG_4 (node))
fputs (" tree_4", file);
if (TREE_LANG_FLAG_5 (node))
fputs (" tree_5", file);
if (TREE_LANG_FLAG_6 (node))
fputs (" tree_6", file);
/* DECL_ nodes have additional attributes. */
switch (TREE_CODE_CLASS (TREE_CODE (node)))
{
case 'd':
mode = DECL_MODE (node);
if (DECL_EXTERNAL (node))
fputs (" external", file);
if (DECL_NONLOCAL (node))
fputs (" nonlocal", file);
if (DECL_REGISTER (node))
fputs (" regdecl", file);
if (DECL_INLINE (node))
fputs (" inline", file);
if (DECL_BIT_FIELD (node))
fputs (" bit-field", file);
if (DECL_VIRTUAL_P (node))
fputs (" virtual", file);
if (DECL_IGNORED_P (node))
fputs (" ignored", file);
if (DECL_IN_SYSTEM_HEADER (node))
fputs (" in_system_header", file);
if (DECL_LANG_FLAG_0 (node))
fputs (" decl_0", file);
if (DECL_LANG_FLAG_1 (node))
fputs (" decl_1", file);
if (DECL_LANG_FLAG_2 (node))
fputs (" decl_2", file);
if (DECL_LANG_FLAG_3 (node))
fputs (" decl_3", file);
if (DECL_LANG_FLAG_4 (node))
fputs (" decl_4", file);
if (DECL_LANG_FLAG_5 (node))
fputs (" decl_5", file);
if (DECL_LANG_FLAG_6 (node))
fputs (" decl_6", file);
if (DECL_LANG_FLAG_7 (node))
fputs (" decl_7", file);
fprintf (file, " %s", mode_name[(int) mode]);
fprintf (file, " file %s line %d",
DECL_SOURCE_FILE (node), DECL_SOURCE_LINE (node));
print_node (file, "size", DECL_SIZE (node), indent + 4);
indent_to (file, indent + 3);
if (TREE_CODE (node) != FUNCTION_DECL)
fprintf (file, " align %d", DECL_ALIGN (node));
else if (DECL_INLINE (node))
fprintf (file, " frame_size %d", DECL_FRAME_SIZE (node));
else if (DECL_BUILT_IN (node))
fprintf (file, " built-in code %d", DECL_FUNCTION_CODE (node));
if (TREE_CODE (node) == FIELD_DECL)
print_node (file, "bitpos", DECL_FIELD_BITPOS (node), indent + 4);
print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4);
print_node_brief (file, "abstract_origin",
DECL_ABSTRACT_ORIGIN (node), indent + 4);
print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4);
print_node (file, "result", DECL_RESULT (node), indent + 4);
print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4);
print_lang_decl (file, node, indent);
if (DECL_RTL (node) != 0)
{
indent_to (file, indent + 4);
print_rtl (file, DECL_RTL (node));
}
if (DECL_SAVED_INSNS (node) != 0)
{
indent_to (file, indent + 4);
if (TREE_CODE (node) == PARM_DECL)
{
fprintf (file, "incoming-rtl ");
print_rtl (file, DECL_INCOMING_RTL (node));
}
else if (TREE_CODE (node) == FUNCTION_DECL)
{
fprintf (file, "saved-insns ");
fprintf (file, HOST_PTR_PRINTF,
(HOST_WIDE_INT) DECL_SAVED_INSNS (node));
}
}
/* Print the decl chain only if decl is at second level. */
if (indent == 4)
print_node (file, "chain", TREE_CHAIN (node), indent + 4);
else
print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4);
break;
case 't':
if (TYPE_NO_FORCE_BLK (node))
fputs (" no_force_blk", file);
if (TYPE_LANG_FLAG_0 (node))
fputs (" type_0", file);
if (TYPE_LANG_FLAG_1 (node))
fputs (" type_1", file);
if (TYPE_LANG_FLAG_2 (node))
fputs (" type_2", file);
if (TYPE_LANG_FLAG_3 (node))
fputs (" type_3", file);
if (TYPE_LANG_FLAG_4 (node))
fputs (" type_4", file);
if (TYPE_LANG_FLAG_5 (node))
fputs (" type_5", file);
if (TYPE_LANG_FLAG_6 (node))
fputs (" type_6", file);
mode = TYPE_MODE (node);
fprintf (file, " %s", mode_name[(int) mode]);
print_node (file, "size", TYPE_SIZE (node), indent + 4);
indent_to (file, indent + 3);
fprintf (file, " align %d", TYPE_ALIGN (node));
fprintf (file, " symtab %d", TYPE_SYMTAB_ADDRESS (node));
print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4);
if (TREE_CODE (node) == ARRAY_TYPE || TREE_CODE (node) == SET_TYPE)
print_node (file, "domain", TYPE_DOMAIN (node), indent + 4);
else if (TREE_CODE (node) == INTEGER_TYPE
|| TREE_CODE (node) == BOOLEAN_TYPE
|| TREE_CODE (node) == CHAR_TYPE)
{
fprintf (file, " precision %d", TYPE_PRECISION (node));
print_node (file, "min", TYPE_MIN_VALUE (node), indent + 4);
print_node (file, "max", TYPE_MAX_VALUE (node), indent + 4);
}
else if (TREE_CODE (node) == ENUMERAL_TYPE)
{
fprintf (file, " precision %d", TYPE_PRECISION (node));
print_node (file, "min", TYPE_MIN_VALUE (node), indent + 4);
print_node (file, "max", TYPE_MAX_VALUE (node), indent + 4);
print_node (file, "values", TYPE_VALUES (node), indent + 4);
}
else if (TREE_CODE (node) == REAL_TYPE)
fprintf (file, " precision %d", TYPE_PRECISION (node));
else if (TREE_CODE (node) == RECORD_TYPE
|| TREE_CODE (node) == UNION_TYPE
|| TREE_CODE (node) == QUAL_UNION_TYPE)
print_node (file, "fields", TYPE_FIELDS (node), indent + 4);
else if (TREE_CODE (node) == FUNCTION_TYPE || TREE_CODE (node) == METHOD_TYPE)
{
if (TYPE_METHOD_BASETYPE (node))
print_node_brief (file, "method basetype", TYPE_METHOD_BASETYPE (node), indent + 4);
print_node (file, "arg-types", TYPE_ARG_TYPES (node), indent + 4);
}
if (TYPE_CONTEXT (node))
print_node_brief (file, "context", TYPE_CONTEXT (node), indent + 4);
print_lang_type (file, node, indent);
if (TYPE_POINTER_TO (node) || TREE_CHAIN (node))
indent_to (file, indent + 3);
print_node_brief (file, "pointer_to_this", TYPE_POINTER_TO (node), indent + 4);
print_node_brief (file, "reference_to_this", TYPE_REFERENCE_TO (node), indent + 4);
print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4);
break;
case 'b':
print_node (file, "vars", BLOCK_VARS (node), indent + 4);
print_node (file, "tags", BLOCK_TYPE_TAGS (node), indent + 4);
print_node (file, "supercontext", BLOCK_SUPERCONTEXT (node), indent + 4);
print_node (file, "subblocks", BLOCK_SUBBLOCKS (node), indent + 4);
print_node (file, "chain", BLOCK_CHAIN (node), indent + 4);
print_node (file, "abstract_origin",
BLOCK_ABSTRACT_ORIGIN (node), indent + 4);
return;
case 'e':
case '<':
case '1':
case '2':
case 'r':
case 's':
switch (TREE_CODE (node))
{
case BIND_EXPR:
print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4);
print_node (file, "body", TREE_OPERAND (node, 1), indent + 4);
print_node (file, "block", TREE_OPERAND (node, 2), indent + 4);
return;
}
first_rtl = len = tree_code_length[(int) TREE_CODE (node)];
/* These kinds of nodes contain rtx's, not trees,
after a certain point. Print the rtx's as rtx's. */
switch (TREE_CODE (node))
{
case SAVE_EXPR:
first_rtl = 2;
break;
case CALL_EXPR:
first_rtl = 2;
break;
case METHOD_CALL_EXPR:
first_rtl = 3;
break;
case WITH_CLEANUP_EXPR:
/* Should be defined to be 2. */
first_rtl = 1;
break;
case RTL_EXPR:
first_rtl = 0;
}
for (i = 0; i < len; i++)
{
if (i >= first_rtl)
{
indent_to (file, indent + 4);
fprintf (file, "rtl %d ", i);
if (TREE_OPERAND (node, i))
print_rtl (file, (struct rtx_def *) TREE_OPERAND (node, i));
else
fprintf (file, "(nil)");
fprintf (file, "\n");
}
else
{
char temp[10];
sprintf (temp, "arg %d", i);
print_node (file, temp, TREE_OPERAND (node, i), indent + 4);
}
}
break;
case 'c':
case 'x':
switch (TREE_CODE (node))
{
case INTEGER_CST:
if (TREE_CONSTANT_OVERFLOW (node))
fprintf (file, " overflow");
if (TREE_INT_CST_HIGH (node) == 0)
fprintf (file, " %1u", TREE_INT_CST_LOW (node));
else if (TREE_INT_CST_HIGH (node) == -1
&& TREE_INT_CST_LOW (node) != 0)
fprintf (file, " -%1u", -TREE_INT_CST_LOW (node));
else
fprintf (file,
#if HOST_BITS_PER_WIDE_INT == 64
#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
" 0x%lx%016lx",
#else
" 0x%x%016x",
#endif
#else
#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
" 0x%lx%08lx",
#else
" 0x%x%08x",
#endif
#endif
TREE_INT_CST_HIGH (node), TREE_INT_CST_LOW (node));
break;
case REAL_CST:
#ifndef REAL_IS_NOT_DOUBLE
fprintf (file, " %e", TREE_REAL_CST (node));
#else
{
char *p = (char *) &TREE_REAL_CST (node);
fprintf (file, " 0x");
for (i = 0; i < sizeof TREE_REAL_CST (node); i++)
fprintf (file, "%02x", *p++);
fprintf (file, "");
}
#endif /* REAL_IS_NOT_DOUBLE */
break;
case COMPLEX_CST:
print_node (file, "real", TREE_REALPART (node), indent + 4);
print_node (file, "imag", TREE_IMAGPART (node), indent + 4);
break;
case STRING_CST:
fprintf (file, " \"%s\"", TREE_STRING_POINTER (node));
/* Print the chain at second level. */
if (indent == 4)
print_node (file, "chain", TREE_CHAIN (node), indent + 4);
else
print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4);
break;
case IDENTIFIER_NODE:
print_lang_identifier (file, node, indent);
break;
case TREE_LIST:
print_node (file, "purpose", TREE_PURPOSE (node), indent + 4);
print_node (file, "value", TREE_VALUE (node), indent + 4);
print_node (file, "chain", TREE_CHAIN (node), indent + 4);
break;
case TREE_VEC:
len = TREE_VEC_LENGTH (node);
for (i = 0; i < len; i++)
if (TREE_VEC_ELT (node, i))
{
char temp[10];
sprintf (temp, "elt %d", i);
indent_to (file, indent + 4);
print_node_brief (file, temp, TREE_VEC_ELT (node, i), 0);
}
break;
case OP_IDENTIFIER:
print_node (file, "op1", TREE_PURPOSE (node), indent + 4);
print_node (file, "op2", TREE_VALUE (node), indent + 4);
}
break;
}
fprintf (file, ">");
}

5969
gnu/usr.bin/cc/cc_int/real.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

850
gnu/usr.bin/cc/cc_int/rtl.c Normal file
View File

@ -0,0 +1,850 @@
/* Allocate and read RTL for GNU C Compiler.
Copyright (C) 1987, 1988, 1991, 1994 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.h"
#include <ctype.h>
#include <stdio.h>
#include "rtl.h"
#include "real.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
/* Obstack used for allocating RTL objects.
Between functions, this is the permanent_obstack.
While parsing and expanding a function, this is maybepermanent_obstack
so we can save it if it is an inline function.
During optimization and output, this is function_obstack. */
extern struct obstack *rtl_obstack;
#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
extern long atol();
#endif
/* Indexed by rtx code, gives number of operands for an rtx with that code.
Does NOT include rtx header data (code and links).
This array is initialized in init_rtl. */
int rtx_length[NUM_RTX_CODE + 1];
/* Indexed by rtx code, gives the name of that kind of rtx, as a C string. */
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) NAME ,
char *rtx_name[] = {
#include "rtl.def" /* rtl expressions are documented here */
};
#undef DEF_RTL_EXPR
/* Indexed by machine mode, gives the name of that machine mode.
This name does not include the letters "mode". */
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) NAME,
char *mode_name[(int) MAX_MACHINE_MODE] = {
#include "machmode.def"
#ifdef EXTRA_CC_MODES
EXTRA_CC_NAMES
#endif
};
#undef DEF_MACHMODE
/* Indexed by machine mode, gives the length of the mode, in bytes.
GET_MODE_CLASS uses this. */
#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
/* Indexed by machine mode, gives the length of the mode, in bytes.
GET_MODE_SIZE uses this. */
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) SIZE,
int mode_size[(int) MAX_MACHINE_MODE] = {
#include "machmode.def"
};
#undef DEF_MACHMODE
/* Indexed by machine mode, gives the length of the mode's subunit.
GET_MODE_UNIT_SIZE uses this. */
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) UNIT,
int mode_unit_size[(int) MAX_MACHINE_MODE] = {
#include "machmode.def" /* machine modes are documented here */
};
#undef DEF_MACHMODE
/* Indexed by machine mode, gives next wider natural mode
(QI -> HI -> SI -> DI, etc.) Widening multiply instructions
use this. */
#define DEF_MACHMODE(SYM, NAME, CLASS, SIZE, UNIT, WIDER) \
(enum machine_mode) WIDER,
enum machine_mode mode_wider_mode[(int) MAX_MACHINE_MODE] = {
#include "machmode.def" /* machine modes are documented here */
};
#undef DEF_MACHMODE
/* Indexed by mode class, gives the narrowest mode for each class. */
enum machine_mode class_narrowest_mode[(int) MAX_MODE_CLASS];
/* Indexed by rtx code, gives a sequence of operand-types for
rtx's of that code. The sequence is a C string in which
each character describes one operand. */
char *rtx_format[] = {
/* "*" undefined.
can cause a warning message
"0" field is unused (or used in a phase-dependent manner)
prints nothing
"i" an integer
prints the integer
"n" like "i", but prints entries from `note_insn_name'
"w" an integer of width HOST_BITS_PER_WIDE_INT
prints the integer
"s" a pointer to a string
prints the string
"S" like "s", but optional:
the containing rtx may end before this operand
"e" a pointer to an rtl expression
prints the expression
"E" a pointer to a vector that points to a number of rtl expressions
prints a list of the rtl expressions
"V" like "E", but optional:
the containing rtx may end before this operand
"u" a pointer to another insn
prints the uid of the insn. */
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) FORMAT ,
#include "rtl.def" /* rtl expressions are defined here */
#undef DEF_RTL_EXPR
};
/* Indexed by rtx code, gives a character representing the "class" of
that rtx code. See rtl.def for documentation on the defined classes. */
char rtx_class[] = {
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) CLASS,
#include "rtl.def" /* rtl expressions are defined here */
#undef DEF_RTL_EXPR
};
/* Names for kinds of NOTEs and REG_NOTEs. */
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"};
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" };
/* Allocate an rtx vector of N elements.
Store the length, and initialize all elements to zero. */
rtvec
rtvec_alloc (n)
int n;
{
rtvec rt;
int i;
rt = (rtvec) obstack_alloc (rtl_obstack,
sizeof (struct rtvec_def)
+ (( n - 1) * sizeof (rtunion)));
/* clear out the vector */
PUT_NUM_ELEM(rt, n);
for (i=0; i < n; i++)
rt->elem[i].rtvec = NULL; /* @@ not portable due to rtunion */
return rt;
}
/* Allocate an rtx of code CODE. The CODE is stored in the rtx;
all the rest is initialized to zero. */
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);
/* This function is called more than any other in GCC,
so we manipulate the obstack directly.
Even though rtx objects are word aligned, we may be sharing an obstack
with tree nodes, which may have to be double-word aligned. So align
our length to the alignment mask in the obstack. */
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;
/* We want to clear everything up to the FLD array. Normally, this is
one int, but we don't want to assume that and it isn't very portable
anyway; this is. */
length = (sizeof (struct rtx_def) - sizeof (rtunion) - 1) / sizeof (int);
for (; length >= 0; length--)
((int *) rt)[length] = 0;
PUT_CODE (rt, code);
return rt;
}
/* Free the rtx X and all RTL allocated since X. */
void
rtx_free (x)
rtx x;
{
obstack_free (rtl_obstack, x);
}
/* Create a new copy of an rtx.
Recursively copies the operands of the rtx,
except for those few rtx codes that are sharable. */
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:
/* SCRATCH must be shared because they represent distinct values. */
return orig;
case CONST:
/* CONST can be shared if it contains a SYMBOL_REF. If it contains
a LABEL_REF, it isn't sharable. */
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;
/* A MEM with a constant address is not sharable. The problem is that
the constant address may need to be reloaded. If the mem is shared,
then reloading one copy of this mem will cause all copies to appear
to have been reloaded. */
}
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 (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 '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;
}
/* Similar to `copy_rtx' except that if MAY_SHARE is present, it is
placed in the result directly, rather than being copied. */
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;
}
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;
}
/* Subroutines of read_rtx. */
/* Dump code after printing a message. Used when read_rtx finds
invalid data. */
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 ();
}
/* Read chars from INFILE until a non-whitespace char
and return that. Comments, both Lisp style and C style,
are treated as whitespace.
Tools such as genflags use this function. */
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') ;
}
else if (c == '/')
{
register int prevc;
c = getc (infile);
if (c != '*')
dump_and_abort ('*', c, infile);
prevc = 0;
while (c = getc (infile))
{
if (prevc == '*' && c == '/')
break;
prevc = c;
}
}
else break;
}
return c;
}
/* Read an rtx code name into the buffer STR[].
It is terminated by any of the punctuation chars of rtx printed syntax. */
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;
}
/* Read an rtx in printed representation from INFILE
and return an actual rtx in core constructed accordingly.
read_rtx is not used in the compiler proper, but rather in
the utilities gen*.c that construct C code from machine descriptions. */
rtx
read_rtx (infile)
FILE *infile;
{
register int i, j, list_counter;
RTX_CODE tmp_code;
register char *format_ptr;
/* tmp_char is a buffer used for reading decimal integers
and names of rtx types and machine modes.
Therefore, 256 must be enough. */
char tmp_char[256];
rtx return_rtx;
register int c;
int tmp_int;
HOST_WIDE_INT tmp_wide;
/* Linked list structure for making RTXs: */
struct rtx_list
{
struct rtx_list *next;
rtx value; /* Value of this node... */
};
c = read_skip_spaces (infile); /* Should be open paren. */
if (c != '(')
dump_and_abort ('(', c, infile);
read_name (tmp_char, infile);
tmp_code = UNKNOWN;
for (i=0; i < NUM_RTX_CODE; i++) /* @@ might speed this search up */
{
if (!(strcmp (tmp_char, GET_RTX_NAME (i))))
{
tmp_code = (RTX_CODE) i; /* get value for name */
break;
}
}
if (tmp_code == UNKNOWN)
{
fprintf (stderr,
"Unknown rtx read in rtl.read_rtx(). Code name was %s .",
tmp_char);
}
/* (NIL) stands for an expression that isn't there. */
if (tmp_code == NIL)
{
/* Discard the closeparen. */
while ((c = getc (infile)) && c != ')');
return 0;
}
return_rtx = rtx_alloc (tmp_code); /* if we end up with an insn expression
then we free this space below. */
format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx));
/* If what follows is `: mode ', read it and
store the mode in the 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++)
{
/* 0 means a field for internal use only.
Don't expect it to be present in the input. */
case '0':
break;
case 'e':
case 'u':
XEXP (return_rtx, i) = read_rtx (infile);
break;
case 'V':
/* 'V' is an optional vector: if a closeparen follows,
just store NULL for this element. */
c = read_skip_spaces (infile);
ungetc (c, infile);
if (c == ')')
{
XVEC (return_rtx, i) = 0;
break;
}
/* Now process the vector. */
case 'E':
{
register struct rtx_list *next_rtx, *rtx_list_link;
struct rtx_list *list_rtx;
c = read_skip_spaces (infile);
if (c != '[')
dump_and_abort ('[', c, infile);
/* add expressions to a list, while keeping a count */
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;
}
/* get vector length and allocate it */
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;
}
/* close bracket gotten */
}
break;
case 'S':
/* 'S' is an optional string: if a closeparen follows,
just store NULL for this element. */
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); /* Read the string */
if (c == '\\')
{
c = getc (infile); /* Read the string */
/* \; makes stuff for a C string constant containing
newline and tab. */
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
tmp_wide = atol (tmp_char);
#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;
}
/* This is called once per compilation, before any rtx's are constructed.
It initializes the vector `rtx_length', the extra CC modes, if any,
and computes certain commonly-used modes. */
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]);
/* Make CONST_DOUBLE bigger, if real values are bigger than
it normally expects to have room for.
Note that REAL_VALUE_TYPE is not defined by default,
since tree.h is not included. But the default dfn as `double'
would do no harm. */
#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';
/* Set the GET_RTX_FORMAT of CONST_DOUBLE to a string
of as many `w's as we now have elements. Subtract two from
the size to account for the 'e' and the '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_size[i] = mode_size[(int) CCmode];
mode_unit_size[i] = mode_unit_size[(int) CCmode];
mode_wider_mode[i - 1] = (enum machine_mode) i;
mode_wider_mode[i] = VOIDmode;
}
#endif
/* Find the narrowest mode for each class. */
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);
}
}
}
#ifdef memset
gcc_memset (dest, value, len)
char *dest;
int value;
int len;
{
while (len-- > 0)
*dest++ = value;
}
#endif /* memset */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

5431
gnu/usr.bin/cc/cc_int/stmt.c Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More