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:
parent
5bb6db475f
commit
b75deec600
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=1823
46
gnu/lib/libgcc/Makefile
Normal file
46
gnu/lib/libgcc/Makefile
Normal 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
8
gnu/usr.bin/cc/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
PGMDIR= cc_int cpp cc1 cc cc1plus c++ libgcc
|
||||
SUBDIR= $(PGMDIR)
|
||||
|
||||
.include <bsd.subdir.mk>
|
10
gnu/usr.bin/cc/Makefile.inc
Normal file
10
gnu/usr.bin/cc/Makefile.inc
Normal 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\"
|
13
gnu/usr.bin/cc/c++/Makefile
Normal file
13
gnu/usr.bin/cc/c++/Makefile
Normal 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
535
gnu/usr.bin/cc/c++/g++.c
Normal 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;
|
||||
}
|
18
gnu/usr.bin/cc/cc/Makefile
Normal file
18
gnu/usr.bin/cc/cc/Makefile
Normal 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
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
4896
gnu/usr.bin/cc/cc/gcc.c
Normal file
File diff suppressed because it is too large
Load Diff
13
gnu/usr.bin/cc/cc1/Makefile
Normal file
13
gnu/usr.bin/cc/cc1/Makefile
Normal 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>
|
639
gnu/usr.bin/cc/cc1/c-aux-info.c
Normal file
639
gnu/usr.bin/cc/cc1/c-aux-info.c
Normal 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");
|
||||
}
|
||||
}
|
95
gnu/usr.bin/cc/cc1/c-convert.c
Normal file
95
gnu/usr.bin/cc/cc1/c-convert.c
Normal 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
6797
gnu/usr.bin/cc/cc1/c-decl.c
Normal file
File diff suppressed because it is too large
Load Diff
595
gnu/usr.bin/cc/cc1/c-iterate.c
Normal file
595
gnu/usr.bin/cc/cc1/c-iterate.c
Normal 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
129
gnu/usr.bin/cc/cc1/c-lang.c
Normal 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
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
3530
gnu/usr.bin/cc/cc1/c-parse.c
Normal file
File diff suppressed because it is too large
Load Diff
188
gnu/usr.bin/cc/cc1/c-pragma.c
Normal file
188
gnu/usr.bin/cc/cc1/c-pragma.c
Normal 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 */
|
6384
gnu/usr.bin/cc/cc1/c-typeck.c
Normal file
6384
gnu/usr.bin/cc/cc1/c-typeck.c
Normal file
File diff suppressed because it is too large
Load Diff
13
gnu/usr.bin/cc/cc1plus/Makefile
Normal file
13
gnu/usr.bin/cc/cc1plus/Makefile
Normal 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>
|
2909
gnu/usr.bin/cc/cc1plus/call.c
Normal file
2909
gnu/usr.bin/cc/cc1plus/call.c
Normal file
File diff suppressed because it is too large
Load Diff
4940
gnu/usr.bin/cc/cc1plus/class.c
Normal file
4940
gnu/usr.bin/cc/cc1plus/class.c
Normal file
File diff suppressed because it is too large
Load Diff
116
gnu/usr.bin/cc/cc1plus/class.h
Normal file
116
gnu/usr.bin/cc/cc1plus/class.h
Normal 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;
|
2373
gnu/usr.bin/cc/cc1plus/cp-tree.h
Normal file
2373
gnu/usr.bin/cc/cc1plus/cp-tree.h
Normal file
File diff suppressed because it is too large
Load Diff
2044
gnu/usr.bin/cc/cc1plus/cvt.c
Normal file
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
12030
gnu/usr.bin/cc/cc1plus/decl.c
Normal file
File diff suppressed because it is too large
Load Diff
54
gnu/usr.bin/cc/cc1plus/decl.h
Normal file
54
gnu/usr.bin/cc/cc1plus/decl.h
Normal 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
|
3102
gnu/usr.bin/cc/cc1plus/decl2.c
Normal file
3102
gnu/usr.bin/cc/cc1plus/decl2.c
Normal file
File diff suppressed because it is too large
Load Diff
927
gnu/usr.bin/cc/cc1plus/edsel.c
Normal file
927
gnu/usr.bin/cc/cc1plus/edsel.c
Normal 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
|
217
gnu/usr.bin/cc/cc1plus/errfn.c
Normal file
217
gnu/usr.bin/cc/cc1plus/errfn.c
Normal 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);
|
||||
}
|
1404
gnu/usr.bin/cc/cc1plus/error.c
Normal file
1404
gnu/usr.bin/cc/cc1plus/error.c
Normal file
File diff suppressed because it is too large
Load Diff
1481
gnu/usr.bin/cc/cc1plus/except.c
Normal file
1481
gnu/usr.bin/cc/cc1plus/except.c
Normal file
File diff suppressed because it is too large
Load Diff
275
gnu/usr.bin/cc/cc1plus/expr.c
Normal file
275
gnu/usr.bin/cc/cc1plus/expr.c
Normal 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
988
gnu/usr.bin/cc/cc1plus/gc.c
Normal 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);
|
||||
}
|
197
gnu/usr.bin/cc/cc1plus/hash.h
Normal file
197
gnu/usr.bin/cc/cc1plus/hash.h
Normal 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;
|
||||
}
|
4077
gnu/usr.bin/cc/cc1plus/init.c
Normal file
4077
gnu/usr.bin/cc/cc1plus/init.c
Normal file
File diff suppressed because it is too large
Load Diff
184
gnu/usr.bin/cc/cc1plus/input.c
Normal file
184
gnu/usr.bin/cc/cc1plus/input.c
Normal 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
4818
gnu/usr.bin/cc/cc1plus/lex.c
Normal file
File diff suppressed because it is too large
Load Diff
130
gnu/usr.bin/cc/cc1plus/lex.h
Normal file
130
gnu/usr.bin/cc/cc1plus/lex.h
Normal 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 ();
|
1948
gnu/usr.bin/cc/cc1plus/method.c
Normal file
1948
gnu/usr.bin/cc/cc1plus/method.c
Normal file
File diff suppressed because it is too large
Load Diff
7604
gnu/usr.bin/cc/cc1plus/parse.c
Normal file
7604
gnu/usr.bin/cc/cc1plus/parse.c
Normal file
File diff suppressed because it is too large
Load Diff
84
gnu/usr.bin/cc/cc1plus/parse.h
Normal file
84
gnu/usr.bin/cc/cc1plus/parse.h
Normal 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
2465
gnu/usr.bin/cc/cc1plus/pt.c
Normal file
File diff suppressed because it is too large
Load Diff
167
gnu/usr.bin/cc/cc1plus/ptree.c
Normal file
167
gnu/usr.bin/cc/cc1plus/ptree.c
Normal 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);
|
||||
}
|
3199
gnu/usr.bin/cc/cc1plus/search.c
Normal file
3199
gnu/usr.bin/cc/cc1plus/search.c
Normal file
File diff suppressed because it is too large
Load Diff
1023
gnu/usr.bin/cc/cc1plus/sig.c
Normal file
1023
gnu/usr.bin/cc/cc1plus/sig.c
Normal file
File diff suppressed because it is too large
Load Diff
436
gnu/usr.bin/cc/cc1plus/spew.c
Normal file
436
gnu/usr.bin/cc/cc1plus/spew.c
Normal 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
|
1763
gnu/usr.bin/cc/cc1plus/tree.c
Normal file
1763
gnu/usr.bin/cc/cc1plus/tree.c
Normal file
File diff suppressed because it is too large
Load Diff
103
gnu/usr.bin/cc/cc1plus/tree.def
Normal file
103
gnu/usr.bin/cc/cc1plus/tree.def
Normal 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)
|
7233
gnu/usr.bin/cc/cc1plus/typeck.c
Normal file
7233
gnu/usr.bin/cc/cc1plus/typeck.c
Normal file
File diff suppressed because it is too large
Load Diff
1607
gnu/usr.bin/cc/cc1plus/typeck2.c
Normal file
1607
gnu/usr.bin/cc/cc1plus/typeck2.c
Normal file
File diff suppressed because it is too large
Load Diff
839
gnu/usr.bin/cc/cc1plus/xref.c
Normal file
839
gnu/usr.bin/cc/cc1plus/xref.c
Normal 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;
|
||||
}
|
||||
}
|
12
gnu/usr.bin/cc/cc_int/Makefile
Normal file
12
gnu/usr.bin/cc/cc_int/Makefile
Normal 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>
|
2138
gnu/usr.bin/cc/cc_int/aux-output.c
Normal file
2138
gnu/usr.bin/cc/cc_int/aux-output.c
Normal file
File diff suppressed because it is too large
Load Diff
991
gnu/usr.bin/cc/cc_int/bc-emit.c
Normal file
991
gnu/usr.bin/cc/cc_int/bc-emit.c
Normal 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;
|
||||
}
|
788
gnu/usr.bin/cc/cc_int/bc-optab.c
Normal file
788
gnu/usr.bin/cc/cc_int/bc-optab.c
Normal 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 ();
|
||||
}
|
1997
gnu/usr.bin/cc/cc_int/c-common.c
Normal file
1997
gnu/usr.bin/cc/cc_int/c-common.c
Normal file
File diff suppressed because it is too large
Load Diff
762
gnu/usr.bin/cc/cc_int/caller-save.c
Normal file
762
gnu/usr.bin/cc/cc_int/caller-save.c
Normal 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;
|
||||
}
|
3061
gnu/usr.bin/cc/cc_int/calls.c
Normal file
3061
gnu/usr.bin/cc/cc_int/calls.c
Normal file
File diff suppressed because it is too large
Load Diff
10790
gnu/usr.bin/cc/cc_int/combine.c
Normal file
10790
gnu/usr.bin/cc/cc_int/combine.c
Normal file
File diff suppressed because it is too large
Load Diff
460
gnu/usr.bin/cc/cc_int/convert.c
Normal file
460
gnu/usr.bin/cc/cc_int/convert.c
Normal 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
8546
gnu/usr.bin/cc/cc_int/cse.c
Normal file
File diff suppressed because it is too large
Load Diff
2585
gnu/usr.bin/cc/cc_int/dbxout.c
Normal file
2585
gnu/usr.bin/cc/cc_int/dbxout.c
Normal file
File diff suppressed because it is too large
Load Diff
5667
gnu/usr.bin/cc/cc_int/dwarfout.c
Normal file
5667
gnu/usr.bin/cc/cc_int/dwarfout.c
Normal file
File diff suppressed because it is too large
Load Diff
3359
gnu/usr.bin/cc/cc_int/emit-rtl.c
Normal file
3359
gnu/usr.bin/cc/cc_int/emit-rtl.c
Normal file
File diff suppressed because it is too large
Load Diff
1152
gnu/usr.bin/cc/cc_int/explow.c
Normal file
1152
gnu/usr.bin/cc/cc_int/explow.c
Normal file
File diff suppressed because it is too large
Load Diff
3957
gnu/usr.bin/cc/cc_int/expmed.c
Normal file
3957
gnu/usr.bin/cc/cc_int/expmed.c
Normal file
File diff suppressed because it is too large
Load Diff
10192
gnu/usr.bin/cc/cc_int/expr.c
Normal file
10192
gnu/usr.bin/cc/cc_int/expr.c
Normal file
File diff suppressed because it is too large
Load Diff
3069
gnu/usr.bin/cc/cc_int/final.c
Normal file
3069
gnu/usr.bin/cc/cc_int/final.c
Normal file
File diff suppressed because it is too large
Load Diff
2793
gnu/usr.bin/cc/cc_int/flow.c
Normal file
2793
gnu/usr.bin/cc/cc_int/flow.c
Normal file
File diff suppressed because it is too large
Load Diff
4889
gnu/usr.bin/cc/cc_int/fold-const.c
Normal file
4889
gnu/usr.bin/cc/cc_int/fold-const.c
Normal file
File diff suppressed because it is too large
Load Diff
5496
gnu/usr.bin/cc/cc_int/function.c
Normal file
5496
gnu/usr.bin/cc/cc_int/function.c
Normal file
File diff suppressed because it is too large
Load Diff
94
gnu/usr.bin/cc/cc_int/getpwd.c
Normal file
94
gnu/usr.bin/cc/cc_int/getpwd.c
Normal 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 */
|
1680
gnu/usr.bin/cc/cc_int/global.c
Normal file
1680
gnu/usr.bin/cc/cc_int/global.c
Normal file
File diff suppressed because it is too large
Load Diff
14
gnu/usr.bin/cc/cc_int/insn-attrtab.c
Normal file
14
gnu/usr.bin/cc/cc_int/insn-attrtab.c
Normal 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
|
||||
|
3973
gnu/usr.bin/cc/cc_int/insn-emit.c
Normal file
3973
gnu/usr.bin/cc/cc_int/insn-emit.c
Normal file
File diff suppressed because it is too large
Load Diff
533
gnu/usr.bin/cc/cc_int/insn-extract.c
Normal file
533
gnu/usr.bin/cc/cc_int/insn-extract.c
Normal 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 ();
|
||||
}
|
||||
}
|
216
gnu/usr.bin/cc/cc_int/insn-opinit.c
Normal file
216
gnu/usr.bin/cc/cc_int/insn-opinit.c
Normal 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;
|
||||
}
|
6865
gnu/usr.bin/cc/cc_int/insn-output.c
Normal file
6865
gnu/usr.bin/cc/cc_int/insn-output.c
Normal file
File diff suppressed because it is too large
Load Diff
28
gnu/usr.bin/cc/cc_int/insn-peep.c
Normal file
28
gnu/usr.bin/cc/cc_int/insn-peep.c
Normal 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];
|
7138
gnu/usr.bin/cc/cc_int/insn-recog.c
Normal file
7138
gnu/usr.bin/cc/cc_int/insn-recog.c
Normal file
File diff suppressed because it is too large
Load Diff
3035
gnu/usr.bin/cc/cc_int/integrate.c
Normal file
3035
gnu/usr.bin/cc/cc_int/integrate.c
Normal file
File diff suppressed because it is too large
Load Diff
4395
gnu/usr.bin/cc/cc_int/jump.c
Normal file
4395
gnu/usr.bin/cc/cc_int/jump.c
Normal file
File diff suppressed because it is too large
Load Diff
2355
gnu/usr.bin/cc/cc_int/local-alloc.c
Normal file
2355
gnu/usr.bin/cc/cc_int/local-alloc.c
Normal file
File diff suppressed because it is too large
Load Diff
6587
gnu/usr.bin/cc/cc_int/loop.c
Normal file
6587
gnu/usr.bin/cc/cc_int/loop.c
Normal file
File diff suppressed because it is too large
Load Diff
485
gnu/usr.bin/cc/cc_int/obstack.c
Normal file
485
gnu/usr.bin/cc/cc_int/obstack.c
Normal 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__. */
|
4100
gnu/usr.bin/cc/cc_int/optabs.c
Normal file
4100
gnu/usr.bin/cc/cc_int/optabs.c
Normal file
File diff suppressed because it is too large
Load Diff
328
gnu/usr.bin/cc/cc_int/print-rtl.c
Normal file
328
gnu/usr.bin/cc/cc_int/print-rtl.c
Normal 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);
|
||||
}
|
||||
}
|
642
gnu/usr.bin/cc/cc_int/print-tree.c
Normal file
642
gnu/usr.bin/cc/cc_int/print-tree.c
Normal 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
5969
gnu/usr.bin/cc/cc_int/real.c
Normal file
File diff suppressed because it is too large
Load Diff
1970
gnu/usr.bin/cc/cc_int/recog.c
Normal file
1970
gnu/usr.bin/cc/cc_int/recog.c
Normal file
File diff suppressed because it is too large
Load Diff
3008
gnu/usr.bin/cc/cc_int/reg-stack.c
Normal file
3008
gnu/usr.bin/cc/cc_int/reg-stack.c
Normal file
File diff suppressed because it is too large
Load Diff
1856
gnu/usr.bin/cc/cc_int/regclass.c
Normal file
1856
gnu/usr.bin/cc/cc_int/regclass.c
Normal file
File diff suppressed because it is too large
Load Diff
5650
gnu/usr.bin/cc/cc_int/reload.c
Normal file
5650
gnu/usr.bin/cc/cc_int/reload.c
Normal file
File diff suppressed because it is too large
Load Diff
7122
gnu/usr.bin/cc/cc_int/reload1.c
Normal file
7122
gnu/usr.bin/cc/cc_int/reload1.c
Normal file
File diff suppressed because it is too large
Load Diff
4281
gnu/usr.bin/cc/cc_int/reorg.c
Normal file
4281
gnu/usr.bin/cc/cc_int/reorg.c
Normal file
File diff suppressed because it is too large
Load Diff
850
gnu/usr.bin/cc/cc_int/rtl.c
Normal file
850
gnu/usr.bin/cc/cc_int/rtl.c
Normal 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 */
|
1835
gnu/usr.bin/cc/cc_int/rtlanal.c
Normal file
1835
gnu/usr.bin/cc/cc_int/rtlanal.c
Normal file
File diff suppressed because it is too large
Load Diff
4884
gnu/usr.bin/cc/cc_int/sched.c
Normal file
4884
gnu/usr.bin/cc/cc_int/sched.c
Normal file
File diff suppressed because it is too large
Load Diff
1530
gnu/usr.bin/cc/cc_int/sdbout.c
Normal file
1530
gnu/usr.bin/cc/cc_int/sdbout.c
Normal file
File diff suppressed because it is too large
Load Diff
5431
gnu/usr.bin/cc/cc_int/stmt.c
Normal file
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
Loading…
Reference in New Issue
Block a user